response.inl 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /* response.inl
  2. *
  3. * Bufferring for HTTP headers for HTTP response.
  4. * This function are only intended to be used at the server side.
  5. * Optional for HTTP/1.0 and HTTP/1.1, mandatory for HTTP/2.
  6. *
  7. * This file is part of the CivetWeb project.
  8. */
  9. #if defined(NO_RESPONSE_BUFFERING) && defined(USE_HTTP2)
  10. #error "HTTP2 currently works only if NO_RESPONSE_BUFFERING is not set"
  11. #endif
  12. /* Internal function to free header list */
  13. static void
  14. free_buffered_response_header_list(struct mg_connection *conn)
  15. {
  16. #if !defined(NO_RESPONSE_BUFFERING)
  17. while (conn->response_info.num_headers > 0) {
  18. conn->response_info.num_headers--;
  19. mg_free((void *)conn->response_info
  20. .http_headers[conn->response_info.num_headers]
  21. .name);
  22. conn->response_info.http_headers[conn->response_info.num_headers].name =
  23. 0;
  24. mg_free((void *)conn->response_info
  25. .http_headers[conn->response_info.num_headers]
  26. .value);
  27. conn->response_info.http_headers[conn->response_info.num_headers]
  28. .value = 0;
  29. }
  30. #else
  31. (void)conn; /* Nothing to do */
  32. #endif
  33. }
  34. /* Send first line of HTTP/1.x response */
  35. static void
  36. send_http1_response_status_line(struct mg_connection *conn)
  37. {
  38. /* mg_get_response_code_text will never return NULL */
  39. const char *txt = mg_get_response_code_text(conn, conn->status_code);
  40. mg_printf(conn,
  41. "HTTP/%s %i %s\r\n",
  42. conn->request_info.http_version,
  43. conn->status_code,
  44. txt);
  45. }
  46. /* Initialize a new HTTP response
  47. * Parameters:
  48. * conn: Current connection handle.
  49. * status: HTTP status code (e.g., 200 for "OK").
  50. * Return:
  51. * 0: ok
  52. * -1: parameter error
  53. * -2: invalid connection type
  54. * -3: invalid connection status
  55. */
  56. int
  57. mg_response_header_start(struct mg_connection *conn, int status)
  58. {
  59. if ((conn == NULL) || (status < 100) || (status > 999)) {
  60. /* Parameter error */
  61. return -1;
  62. }
  63. if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
  64. || (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
  65. /* Only allowed in server context */
  66. return -2;
  67. }
  68. if (conn->request_state != 0) {
  69. /* only allowed if nothing was sent up to now */
  70. return -3;
  71. }
  72. conn->status_code = status;
  73. conn->request_state = 1;
  74. /* Buffered response is stored, unbuffered response will be sent directly,
  75. * but we can only send HTTP/1.x response here */
  76. #if !defined(NO_RESPONSE_BUFFERING)
  77. free_buffered_response_header_list(conn);
  78. #else
  79. send_http1_response_status_line(conn);
  80. conn->request_state = 1; /* Reset from 10 to 1 */
  81. #endif
  82. return 0;
  83. }
  84. /* Add a new HTTP response header line
  85. * Parameters:
  86. * conn: Current connection handle.
  87. * header: Header name.
  88. * value: Header value.
  89. * value_len: Length of header value, excluding the terminating zero.
  90. * Use -1 for "strlen(value)".
  91. * Return:
  92. * 0: ok
  93. * -1: parameter error
  94. * -2: invalid connection type
  95. * -3: invalid connection status
  96. * -4: too many headers
  97. * -5: out of memory
  98. */
  99. int
  100. mg_response_header_add(struct mg_connection *conn,
  101. const char *header,
  102. const char *value,
  103. int value_len)
  104. {
  105. #if !defined(NO_RESPONSE_BUFFERING)
  106. int hidx;
  107. #endif
  108. if ((conn == NULL) || (header == NULL) || (value == NULL)) {
  109. /* Parameter error */
  110. return -1;
  111. }
  112. if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
  113. || (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
  114. /* Only allowed in server context */
  115. return -2;
  116. }
  117. if (conn->request_state != 1) {
  118. /* only allowed if mg_response_header_start has been called before */
  119. return -3;
  120. }
  121. #if !defined(NO_RESPONSE_BUFFERING)
  122. hidx = conn->response_info.num_headers;
  123. if (hidx >= MG_MAX_HEADERS) {
  124. /* Too many headers */
  125. return -4;
  126. }
  127. /* Alloc new element */
  128. conn->response_info.http_headers[hidx].name =
  129. mg_strdup_ctx(header, conn->phys_ctx);
  130. if (value_len >= 0) {
  131. char *hbuf = mg_malloc_ctx((unsigned)value_len + 1, conn->phys_ctx);
  132. if (hbuf) {
  133. memcpy(hbuf, value, (unsigned)value_len);
  134. hbuf[value_len] = 0;
  135. }
  136. conn->response_info.http_headers[hidx].value = hbuf;
  137. } else {
  138. conn->response_info.http_headers[hidx].value =
  139. mg_strdup_ctx(value, conn->phys_ctx);
  140. }
  141. if ((conn->response_info.http_headers[hidx].name == 0)
  142. || (conn->response_info.http_headers[hidx].value == 0)) {
  143. /* Out of memory */
  144. mg_free((void *)conn->response_info.http_headers[hidx].name);
  145. conn->response_info.http_headers[hidx].name = 0;
  146. mg_free((void *)conn->response_info.http_headers[hidx].value);
  147. conn->response_info.http_headers[hidx].value = 0;
  148. return -5;
  149. }
  150. /* OK, header stored */
  151. conn->response_info.num_headers++;
  152. #else
  153. if (value_len >= 0) {
  154. mg_printf(conn, "%s: %.*s\r\n", header, (int)value_len, value);
  155. } else {
  156. mg_printf(conn, "%s: %s\r\n", header, value);
  157. }
  158. conn->request_state = 1; /* Reset from 10 to 1 */
  159. #endif
  160. return 0;
  161. }
  162. /* forward */
  163. static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS]);
  164. /* Add a complete header string (key + value).
  165. * Parameters:
  166. * conn: Current connection handle.
  167. * http1_headers: Header line(s) in the form "name: value".
  168. * Return:
  169. * >=0: no error, number of header lines added
  170. * -1: parameter error
  171. * -2: invalid connection type
  172. * -3: invalid connection status
  173. * -4: too many headers
  174. * -5: out of memory
  175. */
  176. int
  177. mg_response_header_add_lines(struct mg_connection *conn,
  178. const char *http1_headers)
  179. {
  180. struct mg_header add_hdr[MG_MAX_HEADERS];
  181. int num_hdr, i, ret;
  182. char *workbuffer, *parse;
  183. /* We need to work on a copy of the work buffer, sice parse_http_headers
  184. * will modify */
  185. workbuffer = mg_strdup_ctx(http1_headers, conn->phys_ctx);
  186. if (!workbuffer) {
  187. /* Out of memory */
  188. return -5;
  189. }
  190. /* Call existing method to split header buffer */
  191. parse = workbuffer;
  192. num_hdr = parse_http_headers(&parse, add_hdr);
  193. ret = num_hdr;
  194. for (i = 0; i < num_hdr; i++) {
  195. int lret =
  196. mg_response_header_add(conn, add_hdr[i].name, add_hdr[i].value, -1);
  197. if ((ret > 0) && (lret < 0)) {
  198. /* Store error return value */
  199. ret = lret;
  200. }
  201. }
  202. /* mg_response_header_add created a copy, so we can free the original */
  203. mg_free(workbuffer);
  204. return ret;
  205. }
  206. #if defined USE_HTTP2
  207. static int http2_send_response_headers(struct mg_connection *conn);
  208. #endif
  209. /* Send http response
  210. * Parameters:
  211. * conn: Current connection handle.
  212. * Return:
  213. * 0: ok
  214. * -1: parameter error
  215. * -2: invalid connection type
  216. * -3: invalid connection status
  217. */
  218. int
  219. mg_response_header_send(struct mg_connection *conn)
  220. {
  221. #if !defined(NO_RESPONSE_BUFFERING)
  222. int i;
  223. int has_date = 0;
  224. int has_connection = 0;
  225. #endif
  226. if (conn == NULL) {
  227. /* Parameter error */
  228. return -1;
  229. }
  230. if ((conn->connection_type != CONNECTION_TYPE_REQUEST)
  231. || (conn->protocol_type == PROTOCOL_TYPE_WEBSOCKET)) {
  232. /* Only allowed in server context */
  233. return -2;
  234. }
  235. if (conn->request_state != 1) {
  236. /* only allowed if mg_response_header_start has been called before */
  237. return -3;
  238. }
  239. /* State: 2 */
  240. conn->request_state = 2;
  241. #if !defined(NO_RESPONSE_BUFFERING)
  242. if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) {
  243. #if defined USE_HTTP2
  244. int ret = http2_send_response_headers(conn);
  245. return ret ? 0 : 0; /* todo */
  246. #else
  247. return -2;
  248. #endif
  249. }
  250. /* Send */
  251. send_http1_response_status_line(conn);
  252. for (i = 0; i < conn->response_info.num_headers; i++) {
  253. mg_printf(conn,
  254. "%s: %s\r\n",
  255. conn->response_info.http_headers[i].name,
  256. conn->response_info.http_headers[i].value);
  257. /* Check for some special headers */
  258. if (!mg_strcasecmp("Date", conn->response_info.http_headers[i].name)) {
  259. has_date = 1;
  260. }
  261. if (!mg_strcasecmp("Connection",
  262. conn->response_info.http_headers[i].name)) {
  263. has_connection = 1;
  264. }
  265. }
  266. if (!has_date) {
  267. time_t curtime = time(NULL);
  268. char date[64];
  269. gmt_time_string(date, sizeof(date), &curtime);
  270. mg_printf(conn, "Date: %s\r\n", date);
  271. }
  272. if (!has_connection) {
  273. mg_printf(conn, "Connection: %s\r\n", suggest_connection_header(conn));
  274. }
  275. #endif
  276. mg_write(conn, "\r\n", 2);
  277. conn->request_state = 3;
  278. /* ok */
  279. return 0;
  280. }