00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <config.h>
00022
00023 #include <isc/buffer.h>
00024 #include <isc/httpd.h>
00025 #include <isc/mem.h>
00026 #include <isc/socket.h>
00027 #include <isc/string.h>
00028 #include <isc/task.h>
00029 #include <isc/time.h>
00030 #include <isc/util.h>
00031
00032 #include <string.h>
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #define MSHUTTINGDOWN(cm) ((cm->flags & ISC_HTTPDMGR_FLAGSHUTTINGDOWN) != 0)
00046 #define MSETSHUTTINGDOWN(cm) (cm->flags |= ISC_HTTPDMGR_FLAGSHUTTINGDOWN)
00047
00048 #ifdef DEBUG_HTTPD
00049 #define ENTER(x) do { fprintf(stderr, "ENTER %s\n", (x)); } while (0)
00050 #define EXIT(x) do { fprintf(stderr, "EXIT %s\n", (x)); } while (0)
00051 #define NOTICE(x) do { fprintf(stderr, "NOTICE %s\n", (x)); } while (0)
00052 #else
00053 #define ENTER(x) do { } while(0)
00054 #define EXIT(x) do { } while(0)
00055 #define NOTICE(x) do { } while(0)
00056 #endif
00057
00058 #define HTTP_RECVLEN 1024
00059 #define HTTP_SENDGROW 1024
00060 #define HTTP_SEND_MAXLEN 10240
00061
00062 #define HTTPD_CLOSE 0x0001
00063 #define HTTPD_FOUNDHOST 0x0002
00064
00065
00066 struct isc_httpd {
00067 isc_httpdmgr_t *mgr;
00068 ISC_LINK(isc_httpd_t) link;
00069 unsigned int state;
00070 isc_socket_t *sock;
00071
00072
00073
00074
00075 char recvbuf[HTTP_RECVLEN];
00076 isc_uint32_t recvlen;
00077 char *headers;
00078 unsigned int method;
00079 char *url;
00080 char *querystring;
00081 char *protocol;
00082
00083
00084
00085
00086 int flags;
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111 isc_bufferlist_t bufflist;
00112 char *headerdata;
00113 unsigned int headerlen;
00114 isc_buffer_t headerbuffer;
00115
00116 const char *mimetype;
00117 unsigned int retcode;
00118 const char *retmsg;
00119 isc_buffer_t bodybuffer;
00120 isc_httpdfree_t *freecb;
00121 void *freecb_arg;
00122 };
00123
00124
00125 struct isc_httpdmgr {
00126 isc_mem_t *mctx;
00127 isc_socket_t *sock;
00128 isc_task_t *task;
00129 isc_timermgr_t *timermgr;
00130
00131 isc_httpdclientok_t *client_ok;
00132 isc_httpdondestroy_t *ondestroy;
00133 void *cb_arg;
00134
00135 unsigned int flags;
00136 ISC_LIST(isc_httpd_t) running;
00137
00138 isc_mutex_t lock;
00139
00140 ISC_LIST(isc_httpdurl_t) urls;
00141 isc_httpdaction_t *render_404;
00142 isc_httpdaction_t *render_500;
00143 };
00144
00145
00146
00147
00148 #define ISC_HTTPD_METHODUNKNOWN 0
00149 #define ISC_HTTPD_METHODGET 1
00150 #define ISC_HTTPD_METHODPOST 2
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181 #define ISC_HTTPD_STATEIDLE 0
00182 #define ISC_HTTPD_STATERECV 1
00183 #define ISC_HTTPD_STATERECVDONE 2
00184 #define ISC_HTTPD_STATESEND 3
00185 #define ISC_HTTPD_STATESENDDONE 4
00186
00187 #define ISC_HTTPD_ISRECV(c) ((c)->state == ISC_HTTPD_STATERECV)
00188 #define ISC_HTTPD_ISRECVDONE(c) ((c)->state == ISC_HTTPD_STATERECVDONE)
00189 #define ISC_HTTPD_ISSEND(c) ((c)->state == ISC_HTTPD_STATESEND)
00190 #define ISC_HTTPD_ISSENDDONE(c) ((c)->state == ISC_HTTPD_STATESENDDONE)
00191
00192
00193
00194
00195 #define ISC_HTTPD_SETRECV(c) ((c)->state = ISC_HTTPD_STATERECV)
00196 #define ISC_HTTPD_SETRECVDONE(c) ((c)->state = ISC_HTTPD_STATERECVDONE)
00197 #define ISC_HTTPD_SETSEND(c) ((c)->state = ISC_HTTPD_STATESEND)
00198 #define ISC_HTTPD_SETSENDDONE(c) ((c)->state = ISC_HTTPD_STATESENDDONE)
00199
00200 static void isc_httpd_accept(isc_task_t *, isc_event_t *);
00201 static void isc_httpd_recvdone(isc_task_t *, isc_event_t *);
00202 static void isc_httpd_senddone(isc_task_t *, isc_event_t *);
00203 static void destroy_client(isc_httpd_t **);
00204 static isc_result_t process_request(isc_httpd_t *, int);
00205 static void httpdmgr_destroy(isc_httpdmgr_t *);
00206 static isc_result_t grow_headerspace(isc_httpd_t *);
00207 static void reset_client(isc_httpd_t *httpd);
00208
00209 static isc_httpdaction_t render_404;
00210 static isc_httpdaction_t render_500;
00211
00212 static void
00213 destroy_client(isc_httpd_t **httpdp) {
00214 isc_httpd_t *httpd = *httpdp;
00215 isc_httpdmgr_t *httpdmgr = httpd->mgr;
00216
00217 *httpdp = NULL;
00218
00219 LOCK(&httpdmgr->lock);
00220
00221 isc_socket_detach(&httpd->sock);
00222 ISC_LIST_UNLINK(httpdmgr->running, httpd, link);
00223
00224 if (httpd->headerlen > 0)
00225 isc_mem_put(httpdmgr->mctx, httpd->headerdata,
00226 httpd->headerlen);
00227
00228 isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
00229
00230 UNLOCK(&httpdmgr->lock);
00231
00232 httpdmgr_destroy(httpdmgr);
00233 }
00234
00235 isc_result_t
00236 isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
00237 isc_httpdclientok_t *client_ok,
00238 isc_httpdondestroy_t *ondestroy, void *cb_arg,
00239 isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp)
00240 {
00241 isc_result_t result;
00242 isc_httpdmgr_t *httpd;
00243
00244 REQUIRE(mctx != NULL);
00245 REQUIRE(sock != NULL);
00246 REQUIRE(task != NULL);
00247 REQUIRE(tmgr != NULL);
00248 REQUIRE(httpdp != NULL && *httpdp == NULL);
00249
00250 httpd = isc_mem_get(mctx, sizeof(isc_httpdmgr_t));
00251 if (httpd == NULL)
00252 return (ISC_R_NOMEMORY);
00253
00254 result = isc_mutex_init(&httpd->lock);
00255 if (result != ISC_R_SUCCESS) {
00256 isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t));
00257 return (result);
00258 }
00259 httpd->mctx = NULL;
00260 isc_mem_attach(mctx, &httpd->mctx);
00261 httpd->sock = NULL;
00262 isc_socket_attach(sock, &httpd->sock);
00263 httpd->task = NULL;
00264 isc_task_attach(task, &httpd->task);
00265 httpd->timermgr = tmgr;
00266 httpd->client_ok = client_ok;
00267 httpd->ondestroy = ondestroy;
00268 httpd->cb_arg = cb_arg;
00269
00270 ISC_LIST_INIT(httpd->running);
00271 ISC_LIST_INIT(httpd->urls);
00272
00273
00274 result = isc_socket_listen(sock, SOMAXCONN);
00275 if (result != ISC_R_SUCCESS) {
00276 UNEXPECTED_ERROR(__FILE__, __LINE__,
00277 "isc_socket_listen() failed: %s",
00278 isc_result_totext(result));
00279 goto cleanup;
00280 }
00281
00282 (void)isc_socket_filter(sock, "httpready");
00283
00284 result = isc_socket_accept(sock, task, isc_httpd_accept, httpd);
00285 if (result != ISC_R_SUCCESS)
00286 goto cleanup;
00287
00288 httpd->render_404 = render_404;
00289 httpd->render_500 = render_500;
00290
00291 *httpdp = httpd;
00292 return (ISC_R_SUCCESS);
00293
00294 cleanup:
00295 isc_task_detach(&httpd->task);
00296 isc_socket_detach(&httpd->sock);
00297 isc_mem_detach(&httpd->mctx);
00298 (void)isc_mutex_destroy(&httpd->lock);
00299 isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t));
00300 return (result);
00301 }
00302
00303 static void
00304 httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) {
00305 isc_mem_t *mctx;
00306 isc_httpdurl_t *url;
00307
00308 ENTER("httpdmgr_destroy");
00309
00310 LOCK(&httpdmgr->lock);
00311
00312 if (!MSHUTTINGDOWN(httpdmgr)) {
00313 NOTICE("httpdmgr_destroy not shutting down yet");
00314 UNLOCK(&httpdmgr->lock);
00315 return;
00316 }
00317
00318
00319
00320
00321 if (!ISC_LIST_EMPTY(httpdmgr->running)) {
00322 NOTICE("httpdmgr_destroy clients still active");
00323 UNLOCK(&httpdmgr->lock);
00324 return;
00325 }
00326
00327 NOTICE("httpdmgr_destroy detaching socket, task, and timermgr");
00328
00329 isc_socket_detach(&httpdmgr->sock);
00330 isc_task_detach(&httpdmgr->task);
00331 httpdmgr->timermgr = NULL;
00332
00333
00334
00335
00336
00337 url = ISC_LIST_HEAD(httpdmgr->urls);
00338 while (url != NULL) {
00339 isc_mem_free(httpdmgr->mctx, url->url);
00340 ISC_LIST_UNLINK(httpdmgr->urls, url, link);
00341 isc_mem_put(httpdmgr->mctx, url, sizeof(isc_httpdurl_t));
00342 url = ISC_LIST_HEAD(httpdmgr->urls);
00343 }
00344
00345 UNLOCK(&httpdmgr->lock);
00346 (void)isc_mutex_destroy(&httpdmgr->lock);
00347
00348 if (httpdmgr->ondestroy != NULL)
00349 (httpdmgr->ondestroy)(httpdmgr->cb_arg);
00350
00351 mctx = httpdmgr->mctx;
00352 isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t));
00353
00354 EXIT("httpdmgr_destroy");
00355 }
00356
00357 #define LENGTHOK(s) (httpd->recvbuf - (s) < (int)httpd->recvlen)
00358 #define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN)
00359
00360 static isc_result_t
00361 process_request(isc_httpd_t *httpd, int length) {
00362 char *s;
00363 char *p;
00364 int delim;
00365
00366 ENTER("request");
00367
00368 httpd->recvlen += length;
00369
00370 httpd->recvbuf[httpd->recvlen] = 0;
00371 httpd->headers = NULL;
00372
00373
00374
00375
00376
00377 s = strstr(httpd->recvbuf, "\r\n\r\n");
00378 delim = 1;
00379 if (s == NULL) {
00380 s = strstr(httpd->recvbuf, "\n\n");
00381 delim = 2;
00382 }
00383 if (s == NULL)
00384 return (ISC_R_NOTFOUND);
00385
00386
00387
00388
00389
00390 if (strncmp(httpd->recvbuf, "GET ", 4) == 0) {
00391 httpd->method = ISC_HTTPD_METHODGET;
00392 p = httpd->recvbuf + 4;
00393 } else if (strncmp(httpd->recvbuf, "POST ", 5) == 0) {
00394 httpd->method = ISC_HTTPD_METHODPOST;
00395 p = httpd->recvbuf + 5;
00396 } else {
00397 return (ISC_R_RANGE);
00398 }
00399
00400
00401
00402
00403
00404
00405
00406
00407 s = p;
00408 while (LENGTHOK(s) && BUFLENOK(s) &&
00409 (*s != '\n' && *s != '\r' && *s != '\0' && *s != ' '))
00410 s++;
00411 if (!LENGTHOK(s))
00412 return (ISC_R_NOTFOUND);
00413 if (!BUFLENOK(s))
00414 return (ISC_R_NOMEMORY);
00415 *s = 0;
00416
00417
00418
00419
00420 if ((strncmp(p, "http:/", 6) == 0)
00421 || (strncmp(p, "https:/", 7) == 0)) {
00422
00423 while (*p != '/' && *p != 0)
00424 p++;
00425 if (*p == 0)
00426 return (ISC_R_RANGE);
00427 p++;
00428
00429 while (*p != '/' && *p != 0)
00430 p++;
00431 if (*p == 0)
00432 return (ISC_R_RANGE);
00433 p++;
00434
00435 while (*p != '/' && *p != 0)
00436 p++;
00437 if (*p == 0) {
00438 p--;
00439 *p = '/';
00440 }
00441 }
00442
00443 httpd->url = p;
00444 p = s + delim;
00445 s = p;
00446
00447
00448
00449
00450
00451 httpd->querystring = strchr(httpd->url, '?');
00452 if (httpd->querystring != NULL) {
00453 *(httpd->querystring) = 0;
00454 httpd->querystring++;
00455 }
00456
00457
00458
00459
00460
00461 while (LENGTHOK(s) && BUFLENOK(s) &&
00462 (*s != '\n' && *s != '\r' && *s != '\0'))
00463 s++;
00464 if (!LENGTHOK(s))
00465 return (ISC_R_NOTFOUND);
00466 if (!BUFLENOK(s))
00467 return (ISC_R_NOMEMORY);
00468 *s = 0;
00469 if ((strncmp(p, "HTTP/1.0", 8) != 0)
00470 && (strncmp(p, "HTTP/1.1", 8) != 0))
00471 return (ISC_R_RANGE);
00472 httpd->protocol = p;
00473 p = s + 1;
00474 s = p;
00475
00476 httpd->headers = s;
00477
00478 if (strstr(s, "Connection: close") != NULL)
00479 httpd->flags |= HTTPD_CLOSE;
00480
00481 if (strstr(s, "Host: ") != NULL)
00482 httpd->flags |= HTTPD_FOUNDHOST;
00483
00484
00485
00486
00487 if (strcmp(httpd->protocol, "HTTP/1.1") == 0
00488 && ((httpd->flags & HTTPD_FOUNDHOST) == 0))
00489 return (ISC_R_RANGE);
00490
00491 EXIT("request");
00492
00493 return (ISC_R_SUCCESS);
00494 }
00495
00496 static void
00497 isc_httpd_accept(isc_task_t *task, isc_event_t *ev) {
00498 isc_result_t result;
00499 isc_httpdmgr_t *httpdmgr = ev->ev_arg;
00500 isc_httpd_t *httpd;
00501 isc_region_t r;
00502 isc_socket_newconnev_t *nev = (isc_socket_newconnev_t *)ev;
00503 isc_sockaddr_t peeraddr;
00504
00505 ENTER("accept");
00506
00507 LOCK(&httpdmgr->lock);
00508 if (MSHUTTINGDOWN(httpdmgr)) {
00509 NOTICE("accept shutting down, goto out");
00510 goto out;
00511 }
00512
00513 if (nev->result == ISC_R_CANCELED) {
00514 NOTICE("accept canceled, goto out");
00515 goto out;
00516 }
00517
00518 if (nev->result != ISC_R_SUCCESS) {
00519
00520 NOTICE("accept returned failure, goto requeue");
00521 goto requeue;
00522 }
00523
00524 (void)isc_socket_getpeername(nev->newsocket, &peeraddr);
00525 if (httpdmgr->client_ok != NULL &&
00526 !(httpdmgr->client_ok)(&peeraddr, httpdmgr->cb_arg)) {
00527 isc_socket_detach(&nev->newsocket);
00528 goto requeue;
00529 }
00530
00531 httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t));
00532 if (httpd == NULL) {
00533
00534 NOTICE("accept failed to allocate memory, goto requeue");
00535 isc_socket_detach(&nev->newsocket);
00536 goto requeue;
00537 }
00538
00539 httpd->mgr = httpdmgr;
00540 ISC_LINK_INIT(httpd, link);
00541 ISC_LIST_APPEND(httpdmgr->running, httpd, link);
00542 ISC_HTTPD_SETRECV(httpd);
00543 httpd->sock = nev->newsocket;
00544 isc_socket_setname(httpd->sock, "httpd", NULL);
00545 httpd->flags = 0;
00546
00547
00548
00549
00550 httpd->headerdata = isc_mem_get(httpdmgr->mctx, HTTP_SENDGROW);
00551 if (httpd->headerdata == NULL) {
00552 isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
00553 isc_socket_detach(&nev->newsocket);
00554 goto requeue;
00555 }
00556 httpd->headerlen = HTTP_SENDGROW;
00557 isc_buffer_init(&httpd->headerbuffer, httpd->headerdata,
00558 httpd->headerlen);
00559
00560 ISC_LIST_INIT(httpd->bufflist);
00561
00562 isc_buffer_initnull(&httpd->bodybuffer);
00563 reset_client(httpd);
00564
00565 r.base = (unsigned char *)httpd->recvbuf;
00566 r.length = HTTP_RECVLEN - 1;
00567 result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone,
00568 httpd);
00569
00570 POST(result);
00571 NOTICE("accept queued recv on socket");
00572
00573 requeue:
00574 result = isc_socket_accept(httpdmgr->sock, task, isc_httpd_accept,
00575 httpdmgr);
00576 if (result != ISC_R_SUCCESS) {
00577
00578 NOTICE("accept could not reaccept due to failure");
00579 }
00580
00581 out:
00582 UNLOCK(&httpdmgr->lock);
00583
00584 httpdmgr_destroy(httpdmgr);
00585
00586 isc_event_free(&ev);
00587
00588 EXIT("accept");
00589 }
00590
00591 static isc_result_t
00592 render_404(const char *url, isc_httpdurl_t *urlinfo,
00593 const char *querystring, const char *headers, void *arg,
00594 unsigned int *retcode, const char **retmsg,
00595 const char **mimetype, isc_buffer_t *b,
00596 isc_httpdfree_t **freecb, void **freecb_args)
00597 {
00598 static char msg[] = "No such URL.";
00599
00600 UNUSED(url);
00601 UNUSED(urlinfo);
00602 UNUSED(querystring);
00603 UNUSED(headers);
00604 UNUSED(arg);
00605
00606 *retcode = 404;
00607 *retmsg = "No such URL";
00608 *mimetype = "text/plain";
00609 isc_buffer_reinit(b, msg, strlen(msg));
00610 isc_buffer_add(b, strlen(msg));
00611 *freecb = NULL;
00612 *freecb_args = NULL;
00613
00614 return (ISC_R_SUCCESS);
00615 }
00616
00617 static isc_result_t
00618 render_500(const char *url, isc_httpdurl_t *urlinfo,
00619 const char *querystring, const char *headers, void *arg,
00620 unsigned int *retcode, const char **retmsg,
00621 const char **mimetype, isc_buffer_t *b,
00622 isc_httpdfree_t **freecb, void **freecb_args)
00623 {
00624 static char msg[] = "Internal server failure.";
00625
00626 UNUSED(url);
00627 UNUSED(urlinfo);
00628 UNUSED(querystring);
00629 UNUSED(headers);
00630 UNUSED(arg);
00631
00632 *retcode = 500;
00633 *retmsg = "Internal server failure";
00634 *mimetype = "text/plain";
00635 isc_buffer_reinit(b, msg, strlen(msg));
00636 isc_buffer_add(b, strlen(msg));
00637 *freecb = NULL;
00638 *freecb_args = NULL;
00639
00640 return (ISC_R_SUCCESS);
00641 }
00642
00643 static void
00644 isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
00645 isc_region_t r;
00646 isc_result_t result;
00647 isc_httpd_t *httpd = ev->ev_arg;
00648 isc_socketevent_t *sev = (isc_socketevent_t *)ev;
00649 isc_httpdurl_t *url;
00650 isc_time_t now;
00651 char datebuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
00652
00653 ENTER("recv");
00654
00655 INSIST(ISC_HTTPD_ISRECV(httpd));
00656
00657 if (sev->result != ISC_R_SUCCESS) {
00658 NOTICE("recv destroying client");
00659 destroy_client(&httpd);
00660 goto out;
00661 }
00662
00663 result = process_request(httpd, sev->n);
00664 if (result == ISC_R_NOTFOUND) {
00665 if (httpd->recvlen >= HTTP_RECVLEN - 1) {
00666 destroy_client(&httpd);
00667 goto out;
00668 }
00669 r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen;
00670 r.length = HTTP_RECVLEN - httpd->recvlen - 1;
00671
00672 (void)isc_socket_recv(httpd->sock, &r, 1, task,
00673 isc_httpd_recvdone, httpd);
00674 goto out;
00675 } else if (result != ISC_R_SUCCESS) {
00676 destroy_client(&httpd);
00677 goto out;
00678 }
00679
00680 ISC_HTTPD_SETSEND(httpd);
00681
00682
00683
00684
00685
00686 isc_buffer_initnull(&httpd->bodybuffer);
00687 isc_time_now(&now);
00688 isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf));
00689 url = ISC_LIST_HEAD(httpd->mgr->urls);
00690 while (url != NULL) {
00691 if (strcmp(httpd->url, url->url) == 0)
00692 break;
00693 url = ISC_LIST_NEXT(url, link);
00694 }
00695 if (url == NULL)
00696 result = httpd->mgr->render_404(httpd->url, NULL,
00697 httpd->querystring,
00698 NULL, NULL,
00699 &httpd->retcode,
00700 &httpd->retmsg,
00701 &httpd->mimetype,
00702 &httpd->bodybuffer,
00703 &httpd->freecb,
00704 &httpd->freecb_arg);
00705 else
00706 result = url->action(httpd->url, url,
00707 httpd->querystring,
00708 httpd->headers,
00709 url->action_arg,
00710 &httpd->retcode, &httpd->retmsg,
00711 &httpd->mimetype, &httpd->bodybuffer,
00712 &httpd->freecb, &httpd->freecb_arg);
00713 if (result != ISC_R_SUCCESS) {
00714 result = httpd->mgr->render_500(httpd->url, url,
00715 httpd->querystring,
00716 NULL, NULL,
00717 &httpd->retcode,
00718 &httpd->retmsg,
00719 &httpd->mimetype,
00720 &httpd->bodybuffer,
00721 &httpd->freecb,
00722 &httpd->freecb_arg);
00723 RUNTIME_CHECK(result == ISC_R_SUCCESS);
00724 }
00725
00726 isc_httpd_response(httpd);
00727 isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype);
00728 isc_httpd_addheader(httpd, "Date", datebuf);
00729 isc_httpd_addheader(httpd, "Expires", datebuf);
00730
00731 if (url != NULL && url->isstatic) {
00732 char loadbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
00733 isc_time_formathttptimestamp(&url->loadtime,
00734 loadbuf, sizeof(loadbuf));
00735 isc_httpd_addheader(httpd, "Last-Modified", loadbuf);
00736 isc_httpd_addheader(httpd, "Cache-Control: public", NULL);
00737 } else {
00738 isc_httpd_addheader(httpd, "Last-Modified", datebuf);
00739 isc_httpd_addheader(httpd, "Pragma: no-cache", NULL);
00740 isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
00741 }
00742
00743 isc_httpd_addheader(httpd, "Server: libisc", NULL);
00744 isc_httpd_addheaderuint(httpd, "Content-Length",
00745 isc_buffer_usedlength(&httpd->bodybuffer));
00746 isc_httpd_endheaders(httpd);
00747
00748 ISC_LIST_APPEND(httpd->bufflist, &httpd->headerbuffer, link);
00749
00750
00751
00752
00753
00754 if (isc_buffer_length(&httpd->bodybuffer) > 0)
00755 ISC_LIST_APPEND(httpd->bufflist, &httpd->bodybuffer, link);
00756
00757
00758 (void)isc_socket_sendv(httpd->sock, &httpd->bufflist, task,
00759 isc_httpd_senddone, httpd);
00760
00761 out:
00762 isc_event_free(&ev);
00763 EXIT("recv");
00764 }
00765
00766 void
00767 isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
00768 isc_httpdmgr_t *httpdmgr;
00769 isc_httpd_t *httpd;
00770 httpdmgr = *httpdmgrp;
00771 *httpdmgrp = NULL;
00772
00773 ENTER("isc_httpdmgr_shutdown");
00774
00775 LOCK(&httpdmgr->lock);
00776
00777 MSETSHUTTINGDOWN(httpdmgr);
00778
00779 isc_socket_cancel(httpdmgr->sock, httpdmgr->task, ISC_SOCKCANCEL_ALL);
00780
00781 httpd = ISC_LIST_HEAD(httpdmgr->running);
00782 while (httpd != NULL) {
00783 isc_socket_cancel(httpd->sock, httpdmgr->task,
00784 ISC_SOCKCANCEL_ALL);
00785 httpd = ISC_LIST_NEXT(httpd, link);
00786 }
00787
00788 UNLOCK(&httpdmgr->lock);
00789
00790 EXIT("isc_httpdmgr_shutdown");
00791 }
00792
00793 static isc_result_t
00794 grow_headerspace(isc_httpd_t *httpd) {
00795 char *newspace;
00796 unsigned int newlen;
00797 isc_region_t r;
00798
00799 newlen = httpd->headerlen + HTTP_SENDGROW;
00800 if (newlen > HTTP_SEND_MAXLEN)
00801 return (ISC_R_NOSPACE);
00802
00803 newspace = isc_mem_get(httpd->mgr->mctx, newlen);
00804 if (newspace == NULL)
00805 return (ISC_R_NOMEMORY);
00806 isc_buffer_region(&httpd->headerbuffer, &r);
00807 isc_buffer_reinit(&httpd->headerbuffer, newspace, newlen);
00808
00809 isc_mem_put(httpd->mgr->mctx, r.base, r.length);
00810
00811 return (ISC_R_SUCCESS);
00812 }
00813
00814 isc_result_t
00815 isc_httpd_response(isc_httpd_t *httpd) {
00816 isc_result_t result;
00817 unsigned int needlen;
00818
00819 needlen = strlen(httpd->protocol) + 1;
00820 needlen += 3 + 1;
00821 needlen += strlen(httpd->retmsg) + 2;
00822
00823 while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
00824 result = grow_headerspace(httpd);
00825 if (result != ISC_R_SUCCESS)
00826 return (result);
00827 }
00828
00829 sprintf(isc_buffer_used(&httpd->headerbuffer), "%s %03d %s\r\n",
00830 httpd->protocol, httpd->retcode, httpd->retmsg);
00831 isc_buffer_add(&httpd->headerbuffer, needlen);
00832
00833 return (ISC_R_SUCCESS);
00834 }
00835
00836 isc_result_t
00837 isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
00838 const char *val)
00839 {
00840 isc_result_t result;
00841 unsigned int needlen;
00842
00843 needlen = strlen(name);
00844 if (val != NULL)
00845 needlen += 2 + strlen(val);
00846 needlen += 2;
00847
00848 while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
00849 result = grow_headerspace(httpd);
00850 if (result != ISC_R_SUCCESS)
00851 return (result);
00852 }
00853
00854 if (val != NULL)
00855 sprintf(isc_buffer_used(&httpd->headerbuffer),
00856 "%s: %s\r\n", name, val);
00857 else
00858 sprintf(isc_buffer_used(&httpd->headerbuffer),
00859 "%s\r\n", name);
00860
00861 isc_buffer_add(&httpd->headerbuffer, needlen);
00862
00863 return (ISC_R_SUCCESS);
00864 }
00865
00866 isc_result_t
00867 isc_httpd_endheaders(isc_httpd_t *httpd) {
00868 isc_result_t result;
00869
00870 while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) {
00871 result = grow_headerspace(httpd);
00872 if (result != ISC_R_SUCCESS)
00873 return (result);
00874 }
00875
00876 sprintf(isc_buffer_used(&httpd->headerbuffer), "\r\n");
00877 isc_buffer_add(&httpd->headerbuffer, 2);
00878
00879 return (ISC_R_SUCCESS);
00880 }
00881
00882 isc_result_t
00883 isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
00884 isc_result_t result;
00885 unsigned int needlen;
00886 char buf[sizeof "18446744073709551616"];
00887
00888 sprintf(buf, "%d", val);
00889
00890 needlen = strlen(name);
00891 needlen += 2 + strlen(buf);
00892 needlen += 2;
00893
00894 while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
00895 result = grow_headerspace(httpd);
00896 if (result != ISC_R_SUCCESS)
00897 return (result);
00898 }
00899
00900 sprintf(isc_buffer_used(&httpd->headerbuffer),
00901 "%s: %s\r\n", name, buf);
00902
00903 isc_buffer_add(&httpd->headerbuffer, needlen);
00904
00905 return (ISC_R_SUCCESS);
00906 }
00907
00908 static void
00909 isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) {
00910 isc_httpd_t *httpd = ev->ev_arg;
00911 isc_region_t r;
00912 isc_socketevent_t *sev = (isc_socketevent_t *)ev;
00913
00914 ENTER("senddone");
00915 INSIST(ISC_HTTPD_ISSEND(httpd));
00916
00917
00918
00919
00920
00921
00922 NOTICE("senddone unlinked header");
00923 ISC_LIST_UNLINK(sev->bufferlist, &httpd->headerbuffer, link);
00924
00925
00926
00927
00928
00929
00930
00931
00932 if (httpd->freecb != NULL) {
00933 isc_buffer_t *b = NULL;
00934 if (isc_buffer_length(&httpd->bodybuffer) > 0) {
00935 b = &httpd->bodybuffer;
00936 httpd->freecb(b, httpd->freecb_arg);
00937 }
00938 NOTICE("senddone free callback performed");
00939 }
00940 if (ISC_LINK_LINKED(&httpd->bodybuffer, link)) {
00941 ISC_LIST_UNLINK(sev->bufferlist, &httpd->bodybuffer, link);
00942 NOTICE("senddone body buffer unlinked");
00943 }
00944
00945 if (sev->result != ISC_R_SUCCESS) {
00946 destroy_client(&httpd);
00947 goto out;
00948 }
00949
00950 if ((httpd->flags & HTTPD_CLOSE) != 0) {
00951 destroy_client(&httpd);
00952 goto out;
00953 }
00954
00955 ISC_HTTPD_SETRECV(httpd);
00956
00957 NOTICE("senddone restarting recv on socket");
00958
00959 reset_client(httpd);
00960
00961 r.base = (unsigned char *)httpd->recvbuf;
00962 r.length = HTTP_RECVLEN - 1;
00963
00964 (void)isc_socket_recv(httpd->sock, &r, 1, task,
00965 isc_httpd_recvdone, httpd);
00966
00967 out:
00968 isc_event_free(&ev);
00969 EXIT("senddone");
00970 }
00971
00972 static void
00973 reset_client(isc_httpd_t *httpd) {
00974
00975
00976
00977
00978 INSIST(ISC_HTTPD_ISRECV(httpd));
00979 INSIST(!ISC_LINK_LINKED(&httpd->headerbuffer, link));
00980 INSIST(!ISC_LINK_LINKED(&httpd->bodybuffer, link));
00981
00982 httpd->recvbuf[0] = 0;
00983 httpd->recvlen = 0;
00984 httpd->headers = NULL;
00985 httpd->method = ISC_HTTPD_METHODUNKNOWN;
00986 httpd->url = NULL;
00987 httpd->querystring = NULL;
00988 httpd->protocol = NULL;
00989 httpd->flags = 0;
00990
00991 isc_buffer_clear(&httpd->headerbuffer);
00992 isc_buffer_invalidate(&httpd->bodybuffer);
00993 }
00994
00995 isc_result_t
00996 isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
00997 isc_httpdaction_t *func, void *arg)
00998 {
00999 return (isc_httpdmgr_addurl2(httpdmgr, url, ISC_FALSE, func, arg));
01000 }
01001
01002 isc_result_t
01003 isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
01004 isc_boolean_t isstatic,
01005 isc_httpdaction_t *func, void *arg)
01006 {
01007 isc_httpdurl_t *item;
01008
01009 if (url == NULL) {
01010 httpdmgr->render_404 = func;
01011 return (ISC_R_SUCCESS);
01012 }
01013
01014 item = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpdurl_t));
01015 if (item == NULL)
01016 return (ISC_R_NOMEMORY);
01017
01018 item->url = isc_mem_strdup(httpdmgr->mctx, url);
01019 if (item->url == NULL) {
01020 isc_mem_put(httpdmgr->mctx, item, sizeof(isc_httpdurl_t));
01021 return (ISC_R_NOMEMORY);
01022 }
01023
01024 item->action = func;
01025 item->action_arg = arg;
01026 item->isstatic = isstatic;
01027 isc_time_now(&item->loadtime);
01028
01029 ISC_LINK_INIT(item, link);
01030 ISC_LIST_APPEND(httpdmgr->urls, item, link);
01031
01032 return (ISC_R_SUCCESS);
01033 }