Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
response.inl
Go to the documentation of this file.
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
10#if defined(NO_RESPONSE_BUFFERING) && defined(USE_HTTP2)
11#error "HTTP2 works only if NO_RESPONSE_BUFFERING is not set"
12#endif
13
14
15/* Internal function to free header list */
16static void
18{
19#if !defined(NO_RESPONSE_BUFFERING)
20 while (conn->response_info.num_headers > 0) {
22 mg_free((void *)conn->response_info
24 .name);
26 0;
27 mg_free((void *)conn->response_info
29 .value);
31 .value = 0;
32 }
33#else
34 (void)conn; /* Nothing to do */
35#endif
36}
37
38
39/* Send first line of HTTP/1.x response */
40static void
42{
43 const char *status_txt;
44 const char *http_version = conn->request_info.http_version;
45 int status_code = conn->status_code;
46
47 if ((status_code < 100) || (status_code > 999)) {
48 /* Set invalid status code to "500 Internal Server Error" */
49 status_code = 500;
50 }
51 if (!http_version) {
52 http_version = "1.0";
53 }
54
55 /* mg_get_response_code_text will never return NULL */
56 status_txt = mg_get_response_code_text(conn, conn->status_code);
57
58 mg_printf(conn, "HTTP/%s %i %s\r\n", http_version, status_code, status_txt);
59}
60
61
62/* Initialize a new HTTP response
63 * Parameters:
64 * conn: Current connection handle.
65 * status: HTTP status code (e.g., 200 for "OK").
66 * Return:
67 * 0: ok
68 * -1: parameter error
69 * -2: invalid connection type
70 * -3: invalid connection status
71 */
72int
73mg_response_header_start(struct mg_connection *conn, int status)
74{
75 if ((conn == NULL) || (status < 100) || (status > 999)) {
76 /* Parameter error */
77 return -1;
78 }
81 /* Only allowed in server context */
82 return -2;
83 }
84 if (conn->request_state != 0) {
85 /* only allowed if nothing was sent up to now */
86 return -3;
87 }
88 conn->status_code = status;
89 conn->request_state = 1;
90
91 /* Buffered response is stored, unbuffered response will be sent directly,
92 * but we can only send HTTP/1.x response here */
93#if !defined(NO_RESPONSE_BUFFERING)
95#else
97 conn->request_state = 1; /* Reset from 10 to 1 */
98#endif
99
100 return 0;
101}
102
103
104/* Add a new HTTP response header line
105 * Parameters:
106 * conn: Current connection handle.
107 * header: Header name.
108 * value: Header value.
109 * value_len: Length of header value, excluding the terminating zero.
110 * Use -1 for "strlen(value)".
111 * Return:
112 * 0: ok
113 * -1: parameter error
114 * -2: invalid connection type
115 * -3: invalid connection status
116 * -4: too many headers
117 * -5: out of memory
118 */
119int
121 const char *header,
122 const char *value,
123 int value_len)
124{
125#if !defined(NO_RESPONSE_BUFFERING)
126 int hidx;
127#endif
128
129 if ((conn == NULL) || (header == NULL) || (value == NULL)) {
130 /* Parameter error */
131 return -1;
132 }
135 /* Only allowed in server context */
136 return -2;
137 }
138 if (conn->request_state != 1) {
139 /* only allowed if mg_response_header_start has been called before */
140 return -3;
141 }
142
143#if !defined(NO_RESPONSE_BUFFERING)
144 hidx = conn->response_info.num_headers;
145 if (hidx >= MG_MAX_HEADERS) {
146 /* Too many headers */
147 return -4;
148 }
149
150 /* Alloc new element */
151 conn->response_info.http_headers[hidx].name =
152 mg_strdup_ctx(header, conn->phys_ctx);
153 if (value_len >= 0) {
154 char *hbuf =
155 (char *)mg_malloc_ctx((unsigned)value_len + 1, conn->phys_ctx);
156 if (hbuf) {
157 memcpy(hbuf, value, (unsigned)value_len);
158 hbuf[value_len] = 0;
159 }
160 conn->response_info.http_headers[hidx].value = hbuf;
161 } else {
162 conn->response_info.http_headers[hidx].value =
164 }
165
166 if ((conn->response_info.http_headers[hidx].name == 0)
167 || (conn->response_info.http_headers[hidx].value == 0)) {
168 /* Out of memory */
169 mg_free((void *)conn->response_info.http_headers[hidx].name);
170 conn->response_info.http_headers[hidx].name = 0;
171 mg_free((void *)conn->response_info.http_headers[hidx].value);
172 conn->response_info.http_headers[hidx].value = 0;
173 return -5;
174 }
175
176 /* OK, header stored */
178
179#else
180 if (value_len >= 0) {
181 mg_printf(conn, "%s: %.*s\r\n", header, (int)value_len, value);
182 } else {
183 mg_printf(conn, "%s: %s\r\n", header, value);
184 }
185 conn->request_state = 1; /* Reset from 10 to 1 */
186#endif
187
188 return 0;
189}
190
191
192/* forward */
193static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS]);
194
195
196/* Add a complete header string (key + value).
197 * Parameters:
198 * conn: Current connection handle.
199 * http1_headers: Header line(s) in the form "name: value".
200 * Return:
201 * >=0: no error, number of header lines added
202 * -1: parameter error
203 * -2: invalid connection type
204 * -3: invalid connection status
205 * -4: too many headers
206 * -5: out of memory
207 */
208int
210 const char *http1_headers)
211{
212 struct mg_header add_hdr[MG_MAX_HEADERS];
213 int num_hdr, i, ret;
214 char *workbuffer, *parse;
215
216 /* We need to work on a copy of the work buffer, sice parse_http_headers
217 * will modify */
218 workbuffer = mg_strdup_ctx(http1_headers, conn->phys_ctx);
219 if (!workbuffer) {
220 /* Out of memory */
221 return -5;
222 }
223
224 /* Call existing method to split header buffer */
225 parse = workbuffer;
226 num_hdr = parse_http_headers(&parse, add_hdr);
227 ret = num_hdr;
228
229 for (i = 0; i < num_hdr; i++) {
230 int lret =
231 mg_response_header_add(conn, add_hdr[i].name, add_hdr[i].value, -1);
232 if ((ret > 0) && (lret < 0)) {
233 /* Store error return value */
234 ret = lret;
235 }
236 }
237
238 /* mg_response_header_add created a copy, so we can free the original */
239 mg_free(workbuffer);
240 return ret;
241}
242
243
244#if defined(USE_HTTP2)
245static int http2_send_response_headers(struct mg_connection *conn);
246#endif
247
248
249/* Send http response
250 * Parameters:
251 * conn: Current connection handle.
252 * Return:
253 * 0: ok
254 * -1: parameter error
255 * -2: invalid connection type
256 * -3: invalid connection status
257 */
258int
260{
261#if !defined(NO_RESPONSE_BUFFERING)
262 int i;
263 int has_date = 0;
264 int has_connection = 0;
265#endif
266
267 if (conn == NULL) {
268 /* Parameter error */
269 return -1;
270 }
273 /* Only allowed in server context */
274 return -2;
275 }
276 if (conn->request_state != 1) {
277 /* only allowed if mg_response_header_start has been called before */
278 return -3;
279 }
280
281 /* State: 2 */
282 conn->request_state = 2;
283
284#if !defined(NO_RESPONSE_BUFFERING)
285#if defined(USE_HTTP2)
286 if (conn->protocol_type == PROTOCOL_TYPE_HTTP2) {
287 int ret = http2_send_response_headers(conn);
288 return ret ? 0 : 0; /* todo */
289 }
290#endif
291
292 /* Send */
294 for (i = 0; i < conn->response_info.num_headers; i++) {
295 mg_printf(conn,
296 "%s: %s\r\n",
299
300 /* Check for some special headers */
301 if (!mg_strcasecmp("Date", conn->response_info.http_headers[i].name)) {
302 has_date = 1;
303 }
304 if (!mg_strcasecmp("Connection",
305 conn->response_info.http_headers[i].name)) {
306 has_connection = 1;
307 }
308 }
309
310 if (!has_date) {
311 time_t curtime = time(NULL);
312 char date[64];
313 gmt_time_string(date, sizeof(date), &curtime);
314 mg_printf(conn, "Date: %s\r\n", date);
315 }
316 if (!has_connection) {
317 mg_printf(conn, "Connection: %s\r\n", suggest_connection_header(conn));
318 }
319#endif
320
321 mg_write(conn, "\r\n", 2);
322 conn->request_state = 3;
323
324 /* ok */
325 return 0;
326}
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void value
char name[80]
Definition TGX11.cxx:110
#define mg_malloc_ctx(a, c)
Definition civetweb.c:1494
@ PROTOCOL_TYPE_HTTP2
Definition civetweb.c:2432
@ PROTOCOL_TYPE_WEBSOCKET
Definition civetweb.c:2431
int mg_printf(struct mg_connection *conn, const char *fmt,...)
Definition civetweb.c:6937
const char * mg_get_response_code_text(const struct mg_connection *conn, int response_code)
Definition civetweb.c:4152
static void gmt_time_string(char *buf, size_t buf_len, time_t *t)
Definition civetweb.c:3307
int mg_write(struct mg_connection *conn, const void *buf, size_t len)
Definition civetweb.c:6696
static const char * suggest_connection_header(const struct mg_connection *conn)
Definition civetweb.c:4042
static char * mg_strdup_ctx(const char *str, struct mg_context *ctx)
Definition civetweb.c:3027
int mg_strcasecmp(const char *s1, const char *s2)
Definition civetweb.c:2999
static __inline void mg_free(void *a)
Definition civetweb.c:1489
@ CONNECTION_TYPE_REQUEST
Definition civetweb.c:2425
#define MG_MAX_HEADERS
Definition civetweb.h:141
int mg_response_header_add(struct mg_connection *conn, const char *header, const char *value, int value_len)
Definition response.inl:120
int mg_response_header_send(struct mg_connection *conn)
Definition response.inl:259
static int parse_http_headers(char **buf, struct mg_header hdr[MG_MAX_HEADERS])
int mg_response_header_add_lines(struct mg_connection *conn, const char *http1_headers)
Definition response.inl:209
static void send_http1_response_status_line(struct mg_connection *conn)
Definition response.inl:41
static void free_buffered_response_header_list(struct mg_connection *conn)
Definition response.inl:17
int mg_response_header_start(struct mg_connection *conn, int status)
Definition response.inl:73
int connection_type
Definition civetweb.c:2450
struct mg_response_info response_info
Definition civetweb.c:2459
struct mg_request_info request_info
Definition civetweb.c:2458
struct mg_context * phys_ctx
Definition civetweb.c:2461
const char * value
Definition civetweb.h:145
const char * name
Definition civetweb.h:144
const char * http_version
Definition civetweb.h:161
struct mg_header http_headers[(64)]
Definition civetweb.h:200