summaryrefslogtreecommitdiff
path: root/ot_http.c
diff options
context:
space:
mode:
Diffstat (limited to 'ot_http.c')
-rw-r--r--ot_http.c76
1 files changed, 54 insertions, 22 deletions
diff --git a/ot_http.c b/ot_http.c
index e8ba3da..602ff94 100644
--- a/ot_http.c
+++ b/ot_http.c
@@ -39,9 +39,33 @@ ssize_t g_stats_path_len;
39 39
40enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 }; 40enum { SUCCESS_HTTP_HEADER_LENGTH = 80, SUCCESS_HTTP_SIZE_OFF = 17 };
41 41
42/* Give up a connection: the one place that knows everything hanging off it. 42struct http_data *http_adopt(const int64_t sock) {
43 The slot is released before anything is freed, so that a late event or the 43 struct http_data *cookie = fdstate_cookie(sock), *heap;
44 expiry sweep finds a closed descriptor rather than a freed cookie. */ 44 int interest;
45
46 if (!cookie || !(cookie->flag & STRUCT_HTTP_FLAG_ONSTACK))
47 return cookie;
48
49 if (!(heap = malloc(sizeof(*heap))))
50 return NULL;
51
52 *heap = *cookie;
53 heap->flag &= ~STRUCT_HTTP_FLAG_ONSTACK;
54
55 /* Publishing the cookie is what lets another thread reach this connection,
56 so nothing may touch it afterwards, not even to read what it asked for */
57 interest = heap->interest;
58 fdstate_set_cookie((int)sock, heap);
59
60 if (event_add((int)sock, interest, fdstate_generation((int)sock)) == -1) {
61 fdstate_set_cookie((int)sock, cookie);
62 free(heap);
63 return NULL;
64 }
65 return heap;
66}
67
68/* Give up a connection: the one place that knows everything hanging off it. */
45void http_close(const int64_t sock) { 69void http_close(const int64_t sock) {
46 struct http_data *cookie = fdstate_cookie(sock); 70 struct http_data *cookie = fdstate_cookie(sock);
47 71
@@ -54,7 +78,8 @@ void http_close(const int64_t sock) {
54 buf_reset(&cookie->request); 78 buf_reset(&cookie->request);
55 if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER)) 79 if (cookie->flag & (STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED_IN_TRANSFER))
56 mutex_workqueue_canceltask(sock); 80 mutex_workqueue_canceltask(sock);
57 free(cookie); 81 if (!(cookie->flag & STRUCT_HTTP_FLAG_ONSTACK))
82 free(cookie);
58 } 83 }
59 84
60 event_close((int)sock); 85 event_close((int)sock);
@@ -118,11 +143,9 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
118 batch_add(cookie->batch, outbuf, ws->reply_size - written_size); 143 batch_add(cookie->batch, outbuf, ws->reply_size - written_size);
119 144
120 /* writeable short data sockets just have a tcp timeout */ 145 /* writeable short data sockets just have a tcp timeout */
121 if (!ws->keep_alive) { 146 if (!ws->keep_alive)
122 fdstate_set_expiry(sock, 0); 147 fdstate_set_expiry(sock, 0);
123 http_interest_drop(sock, cookie, EVENT_IN); 148 http_interest_set(sock, cookie, EVENT_OUT);
124 }
125 http_interest_add(sock, cookie, EVENT_OUT);
126 } 149 }
127} 150}
128 151
@@ -135,21 +158,20 @@ static void http_senddata(const int64_t sock, struct ot_workstruct *ws) {
135#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP) 158#define HTTPERROR_403_IP return http_issue_error(sock, ws, CODE_HTTPERROR_403_IP)
136#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404) 159#define HTTPERROR_404 return http_issue_error(sock, ws, CODE_HTTPERROR_404)
137#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500) 160#define HTTPERROR_500 return http_issue_error(sock, ws, CODE_HTTPERROR_500)
138static void http_interest(const int64_t sock, struct http_data *cookie, int what) { 161/* A connection is either being read or being written, never both, so what it
162 waits for is set outright rather than added to and taken away again. The
163 event layer only hears about it when the answer changes. */
164void http_interest_set(const int64_t sock, struct http_data *cookie, int what) {
139 if (cookie->interest == what) 165 if (cookie->interest == what)
140 return; 166 return;
141 cookie->interest = what; 167 cookie->interest = what;
168 /* Still on a stack, so not in the event loop yet: whoever adopts this
169 connection registers whatever it asked for last */
170 if (cookie->flag & STRUCT_HTTP_FLAG_ONSTACK)
171 return;
142 event_modify((int)sock, what, fdstate_generation((int)sock)); 172 event_modify((int)sock, what, fdstate_generation((int)sock));
143} 173}
144 174
145void http_interest_add(const int64_t sock, struct http_data *cookie, int what) {
146 http_interest(sock, cookie, cookie->interest | what);
147}
148
149void http_interest_drop(const int64_t sock, struct http_data *cookie, int what) {
150 http_interest(sock, cookie, cookie->interest & ~what);
151}
152
153ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) { 175ssize_t http_issue_error(const int64_t sock, struct ot_workstruct *ws, int code) {
154 const char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required", 176 const char *error_code[] = {"302 Found", "400 Invalid Request", "400 Invalid Request", "400 Invalid Request", "402 Payment Required",
155 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"}; 177 "403 Not Modest", "403 Access Denied", "404 Not Found", "500 Internal Server Error"};
@@ -194,7 +216,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t
194 216
195 /* If we came here, wait for the answer is over */ 217 /* If we came here, wait for the answer is over */
196 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) { 218 if (cookie->flag & STRUCT_HTTP_FLAG_WAITINGFORTASK) {
197 http_interest_drop(sock, cookie, EVENT_IN); 219 http_interest_set(sock, cookie, 0);
198 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK; 220 cookie->flag &= ~STRUCT_HTTP_FLAG_WAITINGFORTASK;
199 } 221 }
200 222
@@ -245,7 +267,7 @@ ssize_t http_sendiovecdata(const int64_t sock, struct ot_workstruct *ws, size_t
245 } 267 }
246 268
247 fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT_SEND)); 269 fdstate_set_expiry(sock, time_future_seconds(OT_CLIENT_TIMEOUT_SEND));
248 http_interest_add(sock, cookie, EVENT_OUT); 270 http_interest_set(sock, cookie, EVENT_OUT);
249 return 0; 271 return 0;
250} 272}
251 273
@@ -334,13 +356,17 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
334 } 356 }
335#endif 357#endif
336#endif 358#endif
337 /* Pass this task to the worker thread */
338 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED; 359 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED;
339 360
340 /* Clients waiting for us should not easily timeout */ 361 /* Clients waiting for us should not easily timeout */
341 fdstate_set_expiry(sock, 0); 362 fdstate_set_expiry(sock, 0);
363 http_interest_set(sock, cookie, 0);
364
365 /* Everything this connection needs has been written, so it can be given
366 a home of its own and only then be made reachable by a worker thread */
367 if (!http_adopt(sock))
368 HTTPERROR_500;
342 fullscrape_deliver(sock, format); 369 fullscrape_deliver(sock, format);
343 http_interest_drop(sock, cookie, EVENT_IN);
344 return ws->reply_size = -2; 370 return ws->reply_size = -2;
345 } 371 }
346#endif 372#endif
@@ -352,6 +378,9 @@ static ssize_t http_handle_stats(const int64_t sock, struct ot_workstruct *ws, c
352 378
353 /* Complex stats also include expensive memory debugging tools */ 379 /* Complex stats also include expensive memory debugging tools */
354 fdstate_set_expiry(sock, 0); 380 fdstate_set_expiry(sock, 0);
381
382 if (!http_adopt(sock))
383 HTTPERROR_500;
355 stats_deliver(sock, mode); 384 stats_deliver(sock, mode);
356 return ws->reply_size = -2; 385 return ws->reply_size = -2;
357 } 386 }
@@ -434,8 +463,11 @@ static ssize_t http_handle_fullscrape(const int64_t sock, struct ot_workstruct *
434 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED; 463 cookie->flag |= STRUCT_HTTP_FLAG_WAITINGFORTASK | STRUCT_HTTP_FLAG_CHUNKED;
435 /* Clients waiting for us should not easily timeout */ 464 /* Clients waiting for us should not easily timeout */
436 fdstate_set_expiry(sock, 0); 465 fdstate_set_expiry(sock, 0);
466 http_interest_set(sock, cookie, 0);
467
468 if (!http_adopt(sock))
469 HTTPERROR_500;
437 fullscrape_deliver(sock, format); 470 fullscrape_deliver(sock, format);
438 http_interest_drop(sock, cookie, EVENT_IN);
439 return ws->reply_size = -2; 471 return ws->reply_size = -2;
440} 472}
441#endif 473#endif