2
0

response.inl 8.5 KB

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