1*00b67f09SDavid van Moolenbroek /* $NetBSD: httpd.c,v 1.8 2015/07/08 17:28:59 christos Exp $ */
2*00b67f09SDavid van Moolenbroek
3*00b67f09SDavid van Moolenbroek /*
4*00b67f09SDavid van Moolenbroek * Copyright (C) 2006-2008, 2010-2015 Internet Systems Consortium, Inc. ("ISC")
5*00b67f09SDavid van Moolenbroek *
6*00b67f09SDavid van Moolenbroek * Permission to use, copy, modify, and/or distribute this software for any
7*00b67f09SDavid van Moolenbroek * purpose with or without fee is hereby granted, provided that the above
8*00b67f09SDavid van Moolenbroek * copyright notice and this permission notice appear in all copies.
9*00b67f09SDavid van Moolenbroek *
10*00b67f09SDavid van Moolenbroek * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11*00b67f09SDavid van Moolenbroek * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12*00b67f09SDavid van Moolenbroek * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13*00b67f09SDavid van Moolenbroek * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14*00b67f09SDavid van Moolenbroek * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15*00b67f09SDavid van Moolenbroek * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16*00b67f09SDavid van Moolenbroek * PERFORMANCE OF THIS SOFTWARE.
17*00b67f09SDavid van Moolenbroek */
18*00b67f09SDavid van Moolenbroek
19*00b67f09SDavid van Moolenbroek /* Id */
20*00b67f09SDavid van Moolenbroek
21*00b67f09SDavid van Moolenbroek /*! \file */
22*00b67f09SDavid van Moolenbroek
23*00b67f09SDavid van Moolenbroek #include <config.h>
24*00b67f09SDavid van Moolenbroek
25*00b67f09SDavid van Moolenbroek #include <isc/buffer.h>
26*00b67f09SDavid van Moolenbroek #include <isc/httpd.h>
27*00b67f09SDavid van Moolenbroek #include <isc/mem.h>
28*00b67f09SDavid van Moolenbroek #include <isc/socket.h>
29*00b67f09SDavid van Moolenbroek #include <isc/string.h>
30*00b67f09SDavid van Moolenbroek #include <isc/task.h>
31*00b67f09SDavid van Moolenbroek #include <isc/time.h>
32*00b67f09SDavid van Moolenbroek #include <isc/util.h>
33*00b67f09SDavid van Moolenbroek
34*00b67f09SDavid van Moolenbroek #include <string.h>
35*00b67f09SDavid van Moolenbroek
36*00b67f09SDavid van Moolenbroek /*%
37*00b67f09SDavid van Moolenbroek * TODO:
38*00b67f09SDavid van Moolenbroek *
39*00b67f09SDavid van Moolenbroek * o Put in better checks to make certain things are passed in correctly.
40*00b67f09SDavid van Moolenbroek * This includes a magic number for externally-visible structures,
41*00b67f09SDavid van Moolenbroek * checking for NULL-ness before dereferencing, etc.
42*00b67f09SDavid van Moolenbroek * o Make the URL processing external functions which will fill-in a buffer
43*00b67f09SDavid van Moolenbroek * structure we provide, or return an error and we will render a generic
44*00b67f09SDavid van Moolenbroek * page and close the client.
45*00b67f09SDavid van Moolenbroek */
46*00b67f09SDavid van Moolenbroek
47*00b67f09SDavid van Moolenbroek #define MSHUTTINGDOWN(cm) ((cm->flags & ISC_HTTPDMGR_FLAGSHUTTINGDOWN) != 0)
48*00b67f09SDavid van Moolenbroek #define MSETSHUTTINGDOWN(cm) (cm->flags |= ISC_HTTPDMGR_FLAGSHUTTINGDOWN)
49*00b67f09SDavid van Moolenbroek
50*00b67f09SDavid van Moolenbroek #ifdef DEBUG_HTTPD
51*00b67f09SDavid van Moolenbroek #define ENTER(x) do { fprintf(stderr, "ENTER %s\n", (x)); } while (/*CONSTCOND*/0)
52*00b67f09SDavid van Moolenbroek #define EXIT(x) do { fprintf(stderr, "EXIT %s\n", (x)); } while (/*CONSTCOND*/0)
53*00b67f09SDavid van Moolenbroek #define NOTICE(x) do { fprintf(stderr, "NOTICE %s\n", (x)); } while (/*CONSTCOND*/0)
54*00b67f09SDavid van Moolenbroek #else
55*00b67f09SDavid van Moolenbroek #define ENTER(x) do { } while(/*CONSTCOND*/0)
56*00b67f09SDavid van Moolenbroek #define EXIT(x) do { } while(/*CONSTCOND*/0)
57*00b67f09SDavid van Moolenbroek #define NOTICE(x) do { } while(/*CONSTCOND*/0)
58*00b67f09SDavid van Moolenbroek #endif
59*00b67f09SDavid van Moolenbroek
60*00b67f09SDavid van Moolenbroek #define HTTP_RECVLEN 1024
61*00b67f09SDavid van Moolenbroek #define HTTP_SENDGROW 1024
62*00b67f09SDavid van Moolenbroek #define HTTP_SEND_MAXLEN 10240
63*00b67f09SDavid van Moolenbroek
64*00b67f09SDavid van Moolenbroek #define HTTPD_CLOSE 0x0001 /* Got a Connection: close header */
65*00b67f09SDavid van Moolenbroek #define HTTPD_FOUNDHOST 0x0002 /* Got a Host: header */
66*00b67f09SDavid van Moolenbroek
67*00b67f09SDavid van Moolenbroek /*% http client */
68*00b67f09SDavid van Moolenbroek struct isc_httpd {
69*00b67f09SDavid van Moolenbroek isc_httpdmgr_t *mgr; /*%< our parent */
70*00b67f09SDavid van Moolenbroek ISC_LINK(isc_httpd_t) link;
71*00b67f09SDavid van Moolenbroek unsigned int state;
72*00b67f09SDavid van Moolenbroek isc_socket_t *sock;
73*00b67f09SDavid van Moolenbroek
74*00b67f09SDavid van Moolenbroek /*%
75*00b67f09SDavid van Moolenbroek * Received data state.
76*00b67f09SDavid van Moolenbroek */
77*00b67f09SDavid van Moolenbroek char recvbuf[HTTP_RECVLEN]; /*%< receive buffer */
78*00b67f09SDavid van Moolenbroek isc_uint32_t recvlen; /*%< length recv'd */
79*00b67f09SDavid van Moolenbroek char *headers; /*%< set in process_request() */
80*00b67f09SDavid van Moolenbroek unsigned int method;
81*00b67f09SDavid van Moolenbroek char *url;
82*00b67f09SDavid van Moolenbroek char *querystring;
83*00b67f09SDavid van Moolenbroek char *protocol;
84*00b67f09SDavid van Moolenbroek
85*00b67f09SDavid van Moolenbroek /*
86*00b67f09SDavid van Moolenbroek * Flags on the httpd client.
87*00b67f09SDavid van Moolenbroek */
88*00b67f09SDavid van Moolenbroek int flags;
89*00b67f09SDavid van Moolenbroek
90*00b67f09SDavid van Moolenbroek /*%
91*00b67f09SDavid van Moolenbroek * Transmit data state.
92*00b67f09SDavid van Moolenbroek *
93*00b67f09SDavid van Moolenbroek * This is the data buffer we will transmit.
94*00b67f09SDavid van Moolenbroek *
95*00b67f09SDavid van Moolenbroek * This free function pointer is filled in by the rendering function
96*00b67f09SDavid van Moolenbroek * we call. The free function is called after the data is transmitted
97*00b67f09SDavid van Moolenbroek * to the client.
98*00b67f09SDavid van Moolenbroek *
99*00b67f09SDavid van Moolenbroek * The bufflist is the list of buffers we are currently transmitting.
100*00b67f09SDavid van Moolenbroek * The headerdata is where we render our headers to. If we run out of
101*00b67f09SDavid van Moolenbroek * space when rendering a header, we will change the size of our
102*00b67f09SDavid van Moolenbroek * buffer. We will not free it until we are finished, and will
103*00b67f09SDavid van Moolenbroek * allocate an additional HTTP_SENDGROW bytes per header space grow.
104*00b67f09SDavid van Moolenbroek *
105*00b67f09SDavid van Moolenbroek * We currently use two buffers total, one for the headers (which
106*00b67f09SDavid van Moolenbroek * we manage) and another for the client to fill in (which it manages,
107*00b67f09SDavid van Moolenbroek * it provides the space for it, etc) -- we will pass that buffer
108*00b67f09SDavid van Moolenbroek * structure back to the caller, who is responsible for managing the
109*00b67f09SDavid van Moolenbroek * space it may have allocated as backing store for it. This second
110*00b67f09SDavid van Moolenbroek * buffer is bodybuffer, and we only allocate the buffer itself, not
111*00b67f09SDavid van Moolenbroek * the backing store.
112*00b67f09SDavid van Moolenbroek */
113*00b67f09SDavid van Moolenbroek isc_bufferlist_t bufflist;
114*00b67f09SDavid van Moolenbroek char *headerdata; /*%< send header buf */
115*00b67f09SDavid van Moolenbroek unsigned int headerlen; /*%< current header buffer size */
116*00b67f09SDavid van Moolenbroek isc_buffer_t headerbuffer;
117*00b67f09SDavid van Moolenbroek
118*00b67f09SDavid van Moolenbroek const char *mimetype;
119*00b67f09SDavid van Moolenbroek unsigned int retcode;
120*00b67f09SDavid van Moolenbroek const char *retmsg;
121*00b67f09SDavid van Moolenbroek isc_buffer_t bodybuffer;
122*00b67f09SDavid van Moolenbroek isc_httpdfree_t *freecb;
123*00b67f09SDavid van Moolenbroek void *freecb_arg;
124*00b67f09SDavid van Moolenbroek };
125*00b67f09SDavid van Moolenbroek
126*00b67f09SDavid van Moolenbroek /*% lightweight socket manager for httpd output */
127*00b67f09SDavid van Moolenbroek struct isc_httpdmgr {
128*00b67f09SDavid van Moolenbroek isc_mem_t *mctx;
129*00b67f09SDavid van Moolenbroek isc_socket_t *sock; /*%< listening socket */
130*00b67f09SDavid van Moolenbroek isc_task_t *task; /*%< owning task */
131*00b67f09SDavid van Moolenbroek isc_timermgr_t *timermgr;
132*00b67f09SDavid van Moolenbroek
133*00b67f09SDavid van Moolenbroek isc_httpdclientok_t *client_ok; /*%< client validator */
134*00b67f09SDavid van Moolenbroek isc_httpdondestroy_t *ondestroy; /*%< cleanup callback */
135*00b67f09SDavid van Moolenbroek void *cb_arg; /*%< argument for the above */
136*00b67f09SDavid van Moolenbroek
137*00b67f09SDavid van Moolenbroek unsigned int flags;
138*00b67f09SDavid van Moolenbroek ISC_LIST(isc_httpd_t) running; /*%< running clients */
139*00b67f09SDavid van Moolenbroek
140*00b67f09SDavid van Moolenbroek isc_mutex_t lock;
141*00b67f09SDavid van Moolenbroek
142*00b67f09SDavid van Moolenbroek ISC_LIST(isc_httpdurl_t) urls; /*%< urls we manage */
143*00b67f09SDavid van Moolenbroek isc_httpdaction_t *render_404;
144*00b67f09SDavid van Moolenbroek isc_httpdaction_t *render_500;
145*00b67f09SDavid van Moolenbroek };
146*00b67f09SDavid van Moolenbroek
147*00b67f09SDavid van Moolenbroek /*%
148*00b67f09SDavid van Moolenbroek * HTTP methods.
149*00b67f09SDavid van Moolenbroek */
150*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_METHODUNKNOWN 0
151*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_METHODGET 1
152*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_METHODPOST 2
153*00b67f09SDavid van Moolenbroek
154*00b67f09SDavid van Moolenbroek /*%
155*00b67f09SDavid van Moolenbroek * Client states.
156*00b67f09SDavid van Moolenbroek *
157*00b67f09SDavid van Moolenbroek * _IDLE The client is not doing anything at all. This state should
158*00b67f09SDavid van Moolenbroek * only occur just after creation, and just before being
159*00b67f09SDavid van Moolenbroek * destroyed.
160*00b67f09SDavid van Moolenbroek *
161*00b67f09SDavid van Moolenbroek * _RECV The client is waiting for data after issuing a socket recv().
162*00b67f09SDavid van Moolenbroek *
163*00b67f09SDavid van Moolenbroek * _RECVDONE Data has been received, and is being processed.
164*00b67f09SDavid van Moolenbroek *
165*00b67f09SDavid van Moolenbroek * _SEND All data for a response has completed, and a reply was
166*00b67f09SDavid van Moolenbroek * sent via a socket send() call.
167*00b67f09SDavid van Moolenbroek *
168*00b67f09SDavid van Moolenbroek * _SENDDONE Send is completed.
169*00b67f09SDavid van Moolenbroek *
170*00b67f09SDavid van Moolenbroek * Badly formatted state table:
171*00b67f09SDavid van Moolenbroek *
172*00b67f09SDavid van Moolenbroek * IDLE -> RECV when client has a recv() queued.
173*00b67f09SDavid van Moolenbroek *
174*00b67f09SDavid van Moolenbroek * RECV -> RECVDONE when recvdone event received.
175*00b67f09SDavid van Moolenbroek *
176*00b67f09SDavid van Moolenbroek * RECVDONE -> SEND if the data for a reply is at hand.
177*00b67f09SDavid van Moolenbroek *
178*00b67f09SDavid van Moolenbroek * SEND -> RECV when a senddone event was received.
179*00b67f09SDavid van Moolenbroek *
180*00b67f09SDavid van Moolenbroek * At any time -> RECV on error. If RECV fails, the client will
181*00b67f09SDavid van Moolenbroek * self-destroy, closing the socket and freeing memory.
182*00b67f09SDavid van Moolenbroek */
183*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_STATEIDLE 0
184*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_STATERECV 1
185*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_STATERECVDONE 2
186*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_STATESEND 3
187*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_STATESENDDONE 4
188*00b67f09SDavid van Moolenbroek
189*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_ISRECV(c) ((c)->state == ISC_HTTPD_STATERECV)
190*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_ISRECVDONE(c) ((c)->state == ISC_HTTPD_STATERECVDONE)
191*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_ISSEND(c) ((c)->state == ISC_HTTPD_STATESEND)
192*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_ISSENDDONE(c) ((c)->state == ISC_HTTPD_STATESENDDONE)
193*00b67f09SDavid van Moolenbroek
194*00b67f09SDavid van Moolenbroek /*%
195*00b67f09SDavid van Moolenbroek * Overall magic test that means we're not idle.
196*00b67f09SDavid van Moolenbroek */
197*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_SETRECV(c) ((c)->state = ISC_HTTPD_STATERECV)
198*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_SETRECVDONE(c) ((c)->state = ISC_HTTPD_STATERECVDONE)
199*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_SETSEND(c) ((c)->state = ISC_HTTPD_STATESEND)
200*00b67f09SDavid van Moolenbroek #define ISC_HTTPD_SETSENDDONE(c) ((c)->state = ISC_HTTPD_STATESENDDONE)
201*00b67f09SDavid van Moolenbroek
202*00b67f09SDavid van Moolenbroek static void isc_httpd_accept(isc_task_t *, isc_event_t *);
203*00b67f09SDavid van Moolenbroek static void isc_httpd_recvdone(isc_task_t *, isc_event_t *);
204*00b67f09SDavid van Moolenbroek static void isc_httpd_senddone(isc_task_t *, isc_event_t *);
205*00b67f09SDavid van Moolenbroek static void destroy_client(isc_httpd_t **);
206*00b67f09SDavid van Moolenbroek static isc_result_t process_request(isc_httpd_t *, int);
207*00b67f09SDavid van Moolenbroek static void httpdmgr_destroy(isc_httpdmgr_t *);
208*00b67f09SDavid van Moolenbroek static isc_result_t grow_headerspace(isc_httpd_t *);
209*00b67f09SDavid van Moolenbroek static void reset_client(isc_httpd_t *httpd);
210*00b67f09SDavid van Moolenbroek
211*00b67f09SDavid van Moolenbroek static isc_httpdaction_t render_404;
212*00b67f09SDavid van Moolenbroek static isc_httpdaction_t render_500;
213*00b67f09SDavid van Moolenbroek
214*00b67f09SDavid van Moolenbroek static void
destroy_client(isc_httpd_t ** httpdp)215*00b67f09SDavid van Moolenbroek destroy_client(isc_httpd_t **httpdp) {
216*00b67f09SDavid van Moolenbroek isc_httpd_t *httpd = *httpdp;
217*00b67f09SDavid van Moolenbroek isc_httpdmgr_t *httpdmgr = httpd->mgr;
218*00b67f09SDavid van Moolenbroek
219*00b67f09SDavid van Moolenbroek *httpdp = NULL;
220*00b67f09SDavid van Moolenbroek
221*00b67f09SDavid van Moolenbroek LOCK(&httpdmgr->lock);
222*00b67f09SDavid van Moolenbroek
223*00b67f09SDavid van Moolenbroek isc_socket_detach(&httpd->sock);
224*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(httpdmgr->running, httpd, link);
225*00b67f09SDavid van Moolenbroek
226*00b67f09SDavid van Moolenbroek if (httpd->headerlen > 0)
227*00b67f09SDavid van Moolenbroek isc_mem_put(httpdmgr->mctx, httpd->headerdata,
228*00b67f09SDavid van Moolenbroek httpd->headerlen);
229*00b67f09SDavid van Moolenbroek
230*00b67f09SDavid van Moolenbroek isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
231*00b67f09SDavid van Moolenbroek
232*00b67f09SDavid van Moolenbroek UNLOCK(&httpdmgr->lock);
233*00b67f09SDavid van Moolenbroek
234*00b67f09SDavid van Moolenbroek httpdmgr_destroy(httpdmgr);
235*00b67f09SDavid van Moolenbroek }
236*00b67f09SDavid van Moolenbroek
237*00b67f09SDavid van Moolenbroek isc_result_t
isc_httpdmgr_create(isc_mem_t * mctx,isc_socket_t * sock,isc_task_t * task,isc_httpdclientok_t * client_ok,isc_httpdondestroy_t * ondestroy,void * cb_arg,isc_timermgr_t * tmgr,isc_httpdmgr_t ** httpdp)238*00b67f09SDavid van Moolenbroek isc_httpdmgr_create(isc_mem_t *mctx, isc_socket_t *sock, isc_task_t *task,
239*00b67f09SDavid van Moolenbroek isc_httpdclientok_t *client_ok,
240*00b67f09SDavid van Moolenbroek isc_httpdondestroy_t *ondestroy, void *cb_arg,
241*00b67f09SDavid van Moolenbroek isc_timermgr_t *tmgr, isc_httpdmgr_t **httpdp)
242*00b67f09SDavid van Moolenbroek {
243*00b67f09SDavid van Moolenbroek isc_result_t result;
244*00b67f09SDavid van Moolenbroek isc_httpdmgr_t *httpd;
245*00b67f09SDavid van Moolenbroek
246*00b67f09SDavid van Moolenbroek REQUIRE(mctx != NULL);
247*00b67f09SDavid van Moolenbroek REQUIRE(sock != NULL);
248*00b67f09SDavid van Moolenbroek REQUIRE(task != NULL);
249*00b67f09SDavid van Moolenbroek REQUIRE(tmgr != NULL);
250*00b67f09SDavid van Moolenbroek REQUIRE(httpdp != NULL && *httpdp == NULL);
251*00b67f09SDavid van Moolenbroek
252*00b67f09SDavid van Moolenbroek httpd = isc_mem_get(mctx, sizeof(isc_httpdmgr_t));
253*00b67f09SDavid van Moolenbroek if (httpd == NULL)
254*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
255*00b67f09SDavid van Moolenbroek
256*00b67f09SDavid van Moolenbroek result = isc_mutex_init(&httpd->lock);
257*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
258*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t));
259*00b67f09SDavid van Moolenbroek return (result);
260*00b67f09SDavid van Moolenbroek }
261*00b67f09SDavid van Moolenbroek httpd->mctx = NULL;
262*00b67f09SDavid van Moolenbroek isc_mem_attach(mctx, &httpd->mctx);
263*00b67f09SDavid van Moolenbroek httpd->sock = NULL;
264*00b67f09SDavid van Moolenbroek isc_socket_attach(sock, &httpd->sock);
265*00b67f09SDavid van Moolenbroek httpd->task = NULL;
266*00b67f09SDavid van Moolenbroek isc_task_attach(task, &httpd->task);
267*00b67f09SDavid van Moolenbroek httpd->timermgr = tmgr; /* XXXMLG no attach function? */
268*00b67f09SDavid van Moolenbroek httpd->client_ok = client_ok;
269*00b67f09SDavid van Moolenbroek httpd->ondestroy = ondestroy;
270*00b67f09SDavid van Moolenbroek httpd->cb_arg = cb_arg;
271*00b67f09SDavid van Moolenbroek
272*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(httpd->running);
273*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(httpd->urls);
274*00b67f09SDavid van Moolenbroek
275*00b67f09SDavid van Moolenbroek /* XXXMLG ignore errors on isc_socket_listen() */
276*00b67f09SDavid van Moolenbroek result = isc_socket_listen(sock, SOMAXCONN);
277*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
278*00b67f09SDavid van Moolenbroek UNEXPECTED_ERROR(__FILE__, __LINE__,
279*00b67f09SDavid van Moolenbroek "isc_socket_listen() failed: %s",
280*00b67f09SDavid van Moolenbroek isc_result_totext(result));
281*00b67f09SDavid van Moolenbroek goto cleanup;
282*00b67f09SDavid van Moolenbroek }
283*00b67f09SDavid van Moolenbroek
284*00b67f09SDavid van Moolenbroek (void)isc_socket_filter(sock, "httpready");
285*00b67f09SDavid van Moolenbroek
286*00b67f09SDavid van Moolenbroek result = isc_socket_accept(sock, task, isc_httpd_accept, httpd);
287*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
288*00b67f09SDavid van Moolenbroek goto cleanup;
289*00b67f09SDavid van Moolenbroek
290*00b67f09SDavid van Moolenbroek httpd->render_404 = render_404;
291*00b67f09SDavid van Moolenbroek httpd->render_500 = render_500;
292*00b67f09SDavid van Moolenbroek
293*00b67f09SDavid van Moolenbroek *httpdp = httpd;
294*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
295*00b67f09SDavid van Moolenbroek
296*00b67f09SDavid van Moolenbroek cleanup:
297*00b67f09SDavid van Moolenbroek isc_task_detach(&httpd->task);
298*00b67f09SDavid van Moolenbroek isc_socket_detach(&httpd->sock);
299*00b67f09SDavid van Moolenbroek isc_mem_detach(&httpd->mctx);
300*00b67f09SDavid van Moolenbroek (void)isc_mutex_destroy(&httpd->lock);
301*00b67f09SDavid van Moolenbroek isc_mem_put(mctx, httpd, sizeof(isc_httpdmgr_t));
302*00b67f09SDavid van Moolenbroek return (result);
303*00b67f09SDavid van Moolenbroek }
304*00b67f09SDavid van Moolenbroek
305*00b67f09SDavid van Moolenbroek static void
httpdmgr_destroy(isc_httpdmgr_t * httpdmgr)306*00b67f09SDavid van Moolenbroek httpdmgr_destroy(isc_httpdmgr_t *httpdmgr) {
307*00b67f09SDavid van Moolenbroek isc_mem_t *mctx;
308*00b67f09SDavid van Moolenbroek isc_httpdurl_t *url;
309*00b67f09SDavid van Moolenbroek
310*00b67f09SDavid van Moolenbroek ENTER("httpdmgr_destroy");
311*00b67f09SDavid van Moolenbroek
312*00b67f09SDavid van Moolenbroek LOCK(&httpdmgr->lock);
313*00b67f09SDavid van Moolenbroek
314*00b67f09SDavid van Moolenbroek if (!MSHUTTINGDOWN(httpdmgr)) {
315*00b67f09SDavid van Moolenbroek NOTICE("httpdmgr_destroy not shutting down yet");
316*00b67f09SDavid van Moolenbroek UNLOCK(&httpdmgr->lock);
317*00b67f09SDavid van Moolenbroek return;
318*00b67f09SDavid van Moolenbroek }
319*00b67f09SDavid van Moolenbroek
320*00b67f09SDavid van Moolenbroek /*
321*00b67f09SDavid van Moolenbroek * If all clients are not shut down, don't do anything yet.
322*00b67f09SDavid van Moolenbroek */
323*00b67f09SDavid van Moolenbroek if (!ISC_LIST_EMPTY(httpdmgr->running)) {
324*00b67f09SDavid van Moolenbroek NOTICE("httpdmgr_destroy clients still active");
325*00b67f09SDavid van Moolenbroek UNLOCK(&httpdmgr->lock);
326*00b67f09SDavid van Moolenbroek return;
327*00b67f09SDavid van Moolenbroek }
328*00b67f09SDavid van Moolenbroek
329*00b67f09SDavid van Moolenbroek NOTICE("httpdmgr_destroy detaching socket, task, and timermgr");
330*00b67f09SDavid van Moolenbroek
331*00b67f09SDavid van Moolenbroek isc_socket_detach(&httpdmgr->sock);
332*00b67f09SDavid van Moolenbroek isc_task_detach(&httpdmgr->task);
333*00b67f09SDavid van Moolenbroek httpdmgr->timermgr = NULL;
334*00b67f09SDavid van Moolenbroek
335*00b67f09SDavid van Moolenbroek /*
336*00b67f09SDavid van Moolenbroek * Clear out the list of all actions we know about. Just free the
337*00b67f09SDavid van Moolenbroek * memory.
338*00b67f09SDavid van Moolenbroek */
339*00b67f09SDavid van Moolenbroek url = ISC_LIST_HEAD(httpdmgr->urls);
340*00b67f09SDavid van Moolenbroek while (url != NULL) {
341*00b67f09SDavid van Moolenbroek isc_mem_free(httpdmgr->mctx, url->url);
342*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(httpdmgr->urls, url, link);
343*00b67f09SDavid van Moolenbroek isc_mem_put(httpdmgr->mctx, url, sizeof(isc_httpdurl_t));
344*00b67f09SDavid van Moolenbroek url = ISC_LIST_HEAD(httpdmgr->urls);
345*00b67f09SDavid van Moolenbroek }
346*00b67f09SDavid van Moolenbroek
347*00b67f09SDavid van Moolenbroek UNLOCK(&httpdmgr->lock);
348*00b67f09SDavid van Moolenbroek (void)isc_mutex_destroy(&httpdmgr->lock);
349*00b67f09SDavid van Moolenbroek
350*00b67f09SDavid van Moolenbroek if (httpdmgr->ondestroy != NULL)
351*00b67f09SDavid van Moolenbroek (httpdmgr->ondestroy)(httpdmgr->cb_arg);
352*00b67f09SDavid van Moolenbroek
353*00b67f09SDavid van Moolenbroek mctx = httpdmgr->mctx;
354*00b67f09SDavid van Moolenbroek isc_mem_putanddetach(&mctx, httpdmgr, sizeof(isc_httpdmgr_t));
355*00b67f09SDavid van Moolenbroek
356*00b67f09SDavid van Moolenbroek EXIT("httpdmgr_destroy");
357*00b67f09SDavid van Moolenbroek }
358*00b67f09SDavid van Moolenbroek
359*00b67f09SDavid van Moolenbroek #define LENGTHOK(s) (httpd->recvbuf - (s) < (int)httpd->recvlen)
360*00b67f09SDavid van Moolenbroek #define BUFLENOK(s) (httpd->recvbuf - (s) < HTTP_RECVLEN)
361*00b67f09SDavid van Moolenbroek
362*00b67f09SDavid van Moolenbroek static isc_result_t
process_request(isc_httpd_t * httpd,int length)363*00b67f09SDavid van Moolenbroek process_request(isc_httpd_t *httpd, int length) {
364*00b67f09SDavid van Moolenbroek char *s;
365*00b67f09SDavid van Moolenbroek char *p;
366*00b67f09SDavid van Moolenbroek int delim;
367*00b67f09SDavid van Moolenbroek
368*00b67f09SDavid van Moolenbroek ENTER("request");
369*00b67f09SDavid van Moolenbroek
370*00b67f09SDavid van Moolenbroek httpd->recvlen += length;
371*00b67f09SDavid van Moolenbroek
372*00b67f09SDavid van Moolenbroek httpd->recvbuf[httpd->recvlen] = 0;
373*00b67f09SDavid van Moolenbroek httpd->headers = NULL;
374*00b67f09SDavid van Moolenbroek
375*00b67f09SDavid van Moolenbroek /*
376*00b67f09SDavid van Moolenbroek * If we don't find a blank line in our buffer, return that we need
377*00b67f09SDavid van Moolenbroek * more data.
378*00b67f09SDavid van Moolenbroek */
379*00b67f09SDavid van Moolenbroek s = strstr(httpd->recvbuf, "\r\n\r\n");
380*00b67f09SDavid van Moolenbroek delim = 1;
381*00b67f09SDavid van Moolenbroek if (s == NULL) {
382*00b67f09SDavid van Moolenbroek s = strstr(httpd->recvbuf, "\n\n");
383*00b67f09SDavid van Moolenbroek delim = 2;
384*00b67f09SDavid van Moolenbroek }
385*00b67f09SDavid van Moolenbroek if (s == NULL)
386*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
387*00b67f09SDavid van Moolenbroek
388*00b67f09SDavid van Moolenbroek /*
389*00b67f09SDavid van Moolenbroek * Determine if this is a POST or GET method. Any other values will
390*00b67f09SDavid van Moolenbroek * cause an error to be returned.
391*00b67f09SDavid van Moolenbroek */
392*00b67f09SDavid van Moolenbroek if (strncmp(httpd->recvbuf, "GET ", 4) == 0) {
393*00b67f09SDavid van Moolenbroek httpd->method = ISC_HTTPD_METHODGET;
394*00b67f09SDavid van Moolenbroek p = httpd->recvbuf + 4;
395*00b67f09SDavid van Moolenbroek } else if (strncmp(httpd->recvbuf, "POST ", 5) == 0) {
396*00b67f09SDavid van Moolenbroek httpd->method = ISC_HTTPD_METHODPOST;
397*00b67f09SDavid van Moolenbroek p = httpd->recvbuf + 5;
398*00b67f09SDavid van Moolenbroek } else {
399*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
400*00b67f09SDavid van Moolenbroek }
401*00b67f09SDavid van Moolenbroek
402*00b67f09SDavid van Moolenbroek /*
403*00b67f09SDavid van Moolenbroek * From now on, p is the start of our buffer.
404*00b67f09SDavid van Moolenbroek */
405*00b67f09SDavid van Moolenbroek
406*00b67f09SDavid van Moolenbroek /*
407*00b67f09SDavid van Moolenbroek * Extract the URL.
408*00b67f09SDavid van Moolenbroek */
409*00b67f09SDavid van Moolenbroek s = p;
410*00b67f09SDavid van Moolenbroek while (LENGTHOK(s) && BUFLENOK(s) &&
411*00b67f09SDavid van Moolenbroek (*s != '\n' && *s != '\r' && *s != '\0' && *s != ' '))
412*00b67f09SDavid van Moolenbroek s++;
413*00b67f09SDavid van Moolenbroek if (!LENGTHOK(s))
414*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
415*00b67f09SDavid van Moolenbroek if (!BUFLENOK(s))
416*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
417*00b67f09SDavid van Moolenbroek *s = 0;
418*00b67f09SDavid van Moolenbroek
419*00b67f09SDavid van Moolenbroek /*
420*00b67f09SDavid van Moolenbroek * Make the URL relative.
421*00b67f09SDavid van Moolenbroek */
422*00b67f09SDavid van Moolenbroek if ((strncmp(p, "http:/", 6) == 0)
423*00b67f09SDavid van Moolenbroek || (strncmp(p, "https:/", 7) == 0)) {
424*00b67f09SDavid van Moolenbroek /* Skip first / */
425*00b67f09SDavid van Moolenbroek while (*p != '/' && *p != 0)
426*00b67f09SDavid van Moolenbroek p++;
427*00b67f09SDavid van Moolenbroek if (*p == 0)
428*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
429*00b67f09SDavid van Moolenbroek p++;
430*00b67f09SDavid van Moolenbroek /* Skip second / */
431*00b67f09SDavid van Moolenbroek while (*p != '/' && *p != 0)
432*00b67f09SDavid van Moolenbroek p++;
433*00b67f09SDavid van Moolenbroek if (*p == 0)
434*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
435*00b67f09SDavid van Moolenbroek p++;
436*00b67f09SDavid van Moolenbroek /* Find third / */
437*00b67f09SDavid van Moolenbroek while (*p != '/' && *p != 0)
438*00b67f09SDavid van Moolenbroek p++;
439*00b67f09SDavid van Moolenbroek if (*p == 0) {
440*00b67f09SDavid van Moolenbroek p--;
441*00b67f09SDavid van Moolenbroek *p = '/';
442*00b67f09SDavid van Moolenbroek }
443*00b67f09SDavid van Moolenbroek }
444*00b67f09SDavid van Moolenbroek
445*00b67f09SDavid van Moolenbroek httpd->url = p;
446*00b67f09SDavid van Moolenbroek p = s + delim;
447*00b67f09SDavid van Moolenbroek s = p;
448*00b67f09SDavid van Moolenbroek
449*00b67f09SDavid van Moolenbroek /*
450*00b67f09SDavid van Moolenbroek * Now, see if there is a ? mark in the URL. If so, this is
451*00b67f09SDavid van Moolenbroek * part of the query string, and we will split it from the URL.
452*00b67f09SDavid van Moolenbroek */
453*00b67f09SDavid van Moolenbroek httpd->querystring = strchr(httpd->url, '?');
454*00b67f09SDavid van Moolenbroek if (httpd->querystring != NULL) {
455*00b67f09SDavid van Moolenbroek *(httpd->querystring) = 0;
456*00b67f09SDavid van Moolenbroek httpd->querystring++;
457*00b67f09SDavid van Moolenbroek }
458*00b67f09SDavid van Moolenbroek
459*00b67f09SDavid van Moolenbroek /*
460*00b67f09SDavid van Moolenbroek * Extract the HTTP/1.X protocol. We will bounce on anything but
461*00b67f09SDavid van Moolenbroek * HTTP/1.1 for now.
462*00b67f09SDavid van Moolenbroek */
463*00b67f09SDavid van Moolenbroek while (LENGTHOK(s) && BUFLENOK(s) &&
464*00b67f09SDavid van Moolenbroek (*s != '\n' && *s != '\r' && *s != '\0'))
465*00b67f09SDavid van Moolenbroek s++;
466*00b67f09SDavid van Moolenbroek if (!LENGTHOK(s))
467*00b67f09SDavid van Moolenbroek return (ISC_R_NOTFOUND);
468*00b67f09SDavid van Moolenbroek if (!BUFLENOK(s))
469*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
470*00b67f09SDavid van Moolenbroek *s = 0;
471*00b67f09SDavid van Moolenbroek if ((strncmp(p, "HTTP/1.0", 8) != 0)
472*00b67f09SDavid van Moolenbroek && (strncmp(p, "HTTP/1.1", 8) != 0))
473*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
474*00b67f09SDavid van Moolenbroek httpd->protocol = p;
475*00b67f09SDavid van Moolenbroek p = s + 1;
476*00b67f09SDavid van Moolenbroek s = p;
477*00b67f09SDavid van Moolenbroek
478*00b67f09SDavid van Moolenbroek httpd->headers = s;
479*00b67f09SDavid van Moolenbroek
480*00b67f09SDavid van Moolenbroek if (strstr(s, "Connection: close") != NULL)
481*00b67f09SDavid van Moolenbroek httpd->flags |= HTTPD_CLOSE;
482*00b67f09SDavid van Moolenbroek
483*00b67f09SDavid van Moolenbroek if (strstr(s, "Host: ") != NULL)
484*00b67f09SDavid van Moolenbroek httpd->flags |= HTTPD_FOUNDHOST;
485*00b67f09SDavid van Moolenbroek
486*00b67f09SDavid van Moolenbroek /*
487*00b67f09SDavid van Moolenbroek * Standards compliance hooks here.
488*00b67f09SDavid van Moolenbroek */
489*00b67f09SDavid van Moolenbroek if (strcmp(httpd->protocol, "HTTP/1.1") == 0
490*00b67f09SDavid van Moolenbroek && ((httpd->flags & HTTPD_FOUNDHOST) == 0))
491*00b67f09SDavid van Moolenbroek return (ISC_R_RANGE);
492*00b67f09SDavid van Moolenbroek
493*00b67f09SDavid van Moolenbroek EXIT("request");
494*00b67f09SDavid van Moolenbroek
495*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
496*00b67f09SDavid van Moolenbroek }
497*00b67f09SDavid van Moolenbroek
498*00b67f09SDavid van Moolenbroek static void
isc_httpd_accept(isc_task_t * task,isc_event_t * ev)499*00b67f09SDavid van Moolenbroek isc_httpd_accept(isc_task_t *task, isc_event_t *ev) {
500*00b67f09SDavid van Moolenbroek isc_result_t result;
501*00b67f09SDavid van Moolenbroek isc_httpdmgr_t *httpdmgr = ev->ev_arg;
502*00b67f09SDavid van Moolenbroek isc_httpd_t *httpd;
503*00b67f09SDavid van Moolenbroek isc_region_t r;
504*00b67f09SDavid van Moolenbroek isc_socket_newconnev_t *nev = (isc_socket_newconnev_t *)ev;
505*00b67f09SDavid van Moolenbroek isc_sockaddr_t peeraddr;
506*00b67f09SDavid van Moolenbroek
507*00b67f09SDavid van Moolenbroek ENTER("accept");
508*00b67f09SDavid van Moolenbroek
509*00b67f09SDavid van Moolenbroek LOCK(&httpdmgr->lock);
510*00b67f09SDavid van Moolenbroek if (MSHUTTINGDOWN(httpdmgr)) {
511*00b67f09SDavid van Moolenbroek NOTICE("accept shutting down, goto out");
512*00b67f09SDavid van Moolenbroek goto out;
513*00b67f09SDavid van Moolenbroek }
514*00b67f09SDavid van Moolenbroek
515*00b67f09SDavid van Moolenbroek if (nev->result == ISC_R_CANCELED) {
516*00b67f09SDavid van Moolenbroek NOTICE("accept canceled, goto out");
517*00b67f09SDavid van Moolenbroek goto out;
518*00b67f09SDavid van Moolenbroek }
519*00b67f09SDavid van Moolenbroek
520*00b67f09SDavid van Moolenbroek if (nev->result != ISC_R_SUCCESS) {
521*00b67f09SDavid van Moolenbroek /* XXXMLG log failure */
522*00b67f09SDavid van Moolenbroek NOTICE("accept returned failure, goto requeue");
523*00b67f09SDavid van Moolenbroek goto requeue;
524*00b67f09SDavid van Moolenbroek }
525*00b67f09SDavid van Moolenbroek
526*00b67f09SDavid van Moolenbroek (void)isc_socket_getpeername(nev->newsocket, &peeraddr);
527*00b67f09SDavid van Moolenbroek if (httpdmgr->client_ok != NULL &&
528*00b67f09SDavid van Moolenbroek !(httpdmgr->client_ok)(&peeraddr, httpdmgr->cb_arg)) {
529*00b67f09SDavid van Moolenbroek isc_socket_detach(&nev->newsocket);
530*00b67f09SDavid van Moolenbroek goto requeue;
531*00b67f09SDavid van Moolenbroek }
532*00b67f09SDavid van Moolenbroek
533*00b67f09SDavid van Moolenbroek httpd = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpd_t));
534*00b67f09SDavid van Moolenbroek if (httpd == NULL) {
535*00b67f09SDavid van Moolenbroek /* XXXMLG log failure */
536*00b67f09SDavid van Moolenbroek NOTICE("accept failed to allocate memory, goto requeue");
537*00b67f09SDavid van Moolenbroek isc_socket_detach(&nev->newsocket);
538*00b67f09SDavid van Moolenbroek goto requeue;
539*00b67f09SDavid van Moolenbroek }
540*00b67f09SDavid van Moolenbroek
541*00b67f09SDavid van Moolenbroek httpd->mgr = httpdmgr;
542*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(httpd, link);
543*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(httpdmgr->running, httpd, link);
544*00b67f09SDavid van Moolenbroek ISC_HTTPD_SETRECV(httpd);
545*00b67f09SDavid van Moolenbroek httpd->sock = nev->newsocket;
546*00b67f09SDavid van Moolenbroek isc_socket_setname(httpd->sock, "httpd", NULL);
547*00b67f09SDavid van Moolenbroek httpd->flags = 0;
548*00b67f09SDavid van Moolenbroek
549*00b67f09SDavid van Moolenbroek /*
550*00b67f09SDavid van Moolenbroek * Initialize the buffer for our headers.
551*00b67f09SDavid van Moolenbroek */
552*00b67f09SDavid van Moolenbroek httpd->headerdata = isc_mem_get(httpdmgr->mctx, HTTP_SENDGROW);
553*00b67f09SDavid van Moolenbroek if (httpd->headerdata == NULL) {
554*00b67f09SDavid van Moolenbroek isc_mem_put(httpdmgr->mctx, httpd, sizeof(isc_httpd_t));
555*00b67f09SDavid van Moolenbroek isc_socket_detach(&nev->newsocket);
556*00b67f09SDavid van Moolenbroek goto requeue;
557*00b67f09SDavid van Moolenbroek }
558*00b67f09SDavid van Moolenbroek httpd->headerlen = HTTP_SENDGROW;
559*00b67f09SDavid van Moolenbroek isc_buffer_init(&httpd->headerbuffer, httpd->headerdata,
560*00b67f09SDavid van Moolenbroek httpd->headerlen);
561*00b67f09SDavid van Moolenbroek
562*00b67f09SDavid van Moolenbroek ISC_LIST_INIT(httpd->bufflist);
563*00b67f09SDavid van Moolenbroek
564*00b67f09SDavid van Moolenbroek isc_buffer_initnull(&httpd->bodybuffer);
565*00b67f09SDavid van Moolenbroek reset_client(httpd);
566*00b67f09SDavid van Moolenbroek
567*00b67f09SDavid van Moolenbroek r.base = (unsigned char *)httpd->recvbuf;
568*00b67f09SDavid van Moolenbroek r.length = HTTP_RECVLEN - 1;
569*00b67f09SDavid van Moolenbroek result = isc_socket_recv(httpd->sock, &r, 1, task, isc_httpd_recvdone,
570*00b67f09SDavid van Moolenbroek httpd);
571*00b67f09SDavid van Moolenbroek /* FIXME!!! */
572*00b67f09SDavid van Moolenbroek POST(result);
573*00b67f09SDavid van Moolenbroek NOTICE("accept queued recv on socket");
574*00b67f09SDavid van Moolenbroek
575*00b67f09SDavid van Moolenbroek requeue:
576*00b67f09SDavid van Moolenbroek result = isc_socket_accept(httpdmgr->sock, task, isc_httpd_accept,
577*00b67f09SDavid van Moolenbroek httpdmgr);
578*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
579*00b67f09SDavid van Moolenbroek /* XXXMLG what to do? Log failure... */
580*00b67f09SDavid van Moolenbroek NOTICE("accept could not reaccept due to failure");
581*00b67f09SDavid van Moolenbroek }
582*00b67f09SDavid van Moolenbroek
583*00b67f09SDavid van Moolenbroek out:
584*00b67f09SDavid van Moolenbroek UNLOCK(&httpdmgr->lock);
585*00b67f09SDavid van Moolenbroek
586*00b67f09SDavid van Moolenbroek httpdmgr_destroy(httpdmgr);
587*00b67f09SDavid van Moolenbroek
588*00b67f09SDavid van Moolenbroek isc_event_free(&ev);
589*00b67f09SDavid van Moolenbroek
590*00b67f09SDavid van Moolenbroek EXIT("accept");
591*00b67f09SDavid van Moolenbroek }
592*00b67f09SDavid van Moolenbroek
593*00b67f09SDavid van Moolenbroek static isc_result_t
render_404(const char * url,isc_httpdurl_t * urlinfo,const char * querystring,const char * headers,void * arg,unsigned int * retcode,const char ** retmsg,const char ** mimetype,isc_buffer_t * b,isc_httpdfree_t ** freecb,void ** freecb_args)594*00b67f09SDavid van Moolenbroek render_404(const char *url, isc_httpdurl_t *urlinfo,
595*00b67f09SDavid van Moolenbroek const char *querystring, const char *headers, void *arg,
596*00b67f09SDavid van Moolenbroek unsigned int *retcode, const char **retmsg,
597*00b67f09SDavid van Moolenbroek const char **mimetype, isc_buffer_t *b,
598*00b67f09SDavid van Moolenbroek isc_httpdfree_t **freecb, void **freecb_args)
599*00b67f09SDavid van Moolenbroek {
600*00b67f09SDavid van Moolenbroek static char msg[] = "No such URL.";
601*00b67f09SDavid van Moolenbroek
602*00b67f09SDavid van Moolenbroek UNUSED(url);
603*00b67f09SDavid van Moolenbroek UNUSED(urlinfo);
604*00b67f09SDavid van Moolenbroek UNUSED(querystring);
605*00b67f09SDavid van Moolenbroek UNUSED(headers);
606*00b67f09SDavid van Moolenbroek UNUSED(arg);
607*00b67f09SDavid van Moolenbroek
608*00b67f09SDavid van Moolenbroek *retcode = 404;
609*00b67f09SDavid van Moolenbroek *retmsg = "No such URL";
610*00b67f09SDavid van Moolenbroek *mimetype = "text/plain";
611*00b67f09SDavid van Moolenbroek isc_buffer_reinit(b, msg, strlen(msg));
612*00b67f09SDavid van Moolenbroek isc_buffer_add(b, strlen(msg));
613*00b67f09SDavid van Moolenbroek *freecb = NULL;
614*00b67f09SDavid van Moolenbroek *freecb_args = NULL;
615*00b67f09SDavid van Moolenbroek
616*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
617*00b67f09SDavid van Moolenbroek }
618*00b67f09SDavid van Moolenbroek
619*00b67f09SDavid van Moolenbroek static isc_result_t
render_500(const char * url,isc_httpdurl_t * urlinfo,const char * querystring,const char * headers,void * arg,unsigned int * retcode,const char ** retmsg,const char ** mimetype,isc_buffer_t * b,isc_httpdfree_t ** freecb,void ** freecb_args)620*00b67f09SDavid van Moolenbroek render_500(const char *url, isc_httpdurl_t *urlinfo,
621*00b67f09SDavid van Moolenbroek const char *querystring, const char *headers, void *arg,
622*00b67f09SDavid van Moolenbroek unsigned int *retcode, const char **retmsg,
623*00b67f09SDavid van Moolenbroek const char **mimetype, isc_buffer_t *b,
624*00b67f09SDavid van Moolenbroek isc_httpdfree_t **freecb, void **freecb_args)
625*00b67f09SDavid van Moolenbroek {
626*00b67f09SDavid van Moolenbroek static char msg[] = "Internal server failure.";
627*00b67f09SDavid van Moolenbroek
628*00b67f09SDavid van Moolenbroek UNUSED(url);
629*00b67f09SDavid van Moolenbroek UNUSED(urlinfo);
630*00b67f09SDavid van Moolenbroek UNUSED(querystring);
631*00b67f09SDavid van Moolenbroek UNUSED(headers);
632*00b67f09SDavid van Moolenbroek UNUSED(arg);
633*00b67f09SDavid van Moolenbroek
634*00b67f09SDavid van Moolenbroek *retcode = 500;
635*00b67f09SDavid van Moolenbroek *retmsg = "Internal server failure";
636*00b67f09SDavid van Moolenbroek *mimetype = "text/plain";
637*00b67f09SDavid van Moolenbroek isc_buffer_reinit(b, msg, strlen(msg));
638*00b67f09SDavid van Moolenbroek isc_buffer_add(b, strlen(msg));
639*00b67f09SDavid van Moolenbroek *freecb = NULL;
640*00b67f09SDavid van Moolenbroek *freecb_args = NULL;
641*00b67f09SDavid van Moolenbroek
642*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
643*00b67f09SDavid van Moolenbroek }
644*00b67f09SDavid van Moolenbroek
645*00b67f09SDavid van Moolenbroek static void
isc_httpd_recvdone(isc_task_t * task,isc_event_t * ev)646*00b67f09SDavid van Moolenbroek isc_httpd_recvdone(isc_task_t *task, isc_event_t *ev) {
647*00b67f09SDavid van Moolenbroek isc_region_t r;
648*00b67f09SDavid van Moolenbroek isc_result_t result;
649*00b67f09SDavid van Moolenbroek isc_httpd_t *httpd = ev->ev_arg;
650*00b67f09SDavid van Moolenbroek isc_socketevent_t *sev = (isc_socketevent_t *)ev;
651*00b67f09SDavid van Moolenbroek isc_httpdurl_t *url;
652*00b67f09SDavid van Moolenbroek isc_time_t now;
653*00b67f09SDavid van Moolenbroek char datebuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
654*00b67f09SDavid van Moolenbroek
655*00b67f09SDavid van Moolenbroek ENTER("recv");
656*00b67f09SDavid van Moolenbroek
657*00b67f09SDavid van Moolenbroek INSIST(ISC_HTTPD_ISRECV(httpd));
658*00b67f09SDavid van Moolenbroek
659*00b67f09SDavid van Moolenbroek if (sev->result != ISC_R_SUCCESS) {
660*00b67f09SDavid van Moolenbroek NOTICE("recv destroying client");
661*00b67f09SDavid van Moolenbroek destroy_client(&httpd);
662*00b67f09SDavid van Moolenbroek goto out;
663*00b67f09SDavid van Moolenbroek }
664*00b67f09SDavid van Moolenbroek
665*00b67f09SDavid van Moolenbroek result = process_request(httpd, sev->n);
666*00b67f09SDavid van Moolenbroek if (result == ISC_R_NOTFOUND) {
667*00b67f09SDavid van Moolenbroek if (httpd->recvlen >= HTTP_RECVLEN - 1) {
668*00b67f09SDavid van Moolenbroek destroy_client(&httpd);
669*00b67f09SDavid van Moolenbroek goto out;
670*00b67f09SDavid van Moolenbroek }
671*00b67f09SDavid van Moolenbroek r.base = (unsigned char *)httpd->recvbuf + httpd->recvlen;
672*00b67f09SDavid van Moolenbroek r.length = HTTP_RECVLEN - httpd->recvlen - 1;
673*00b67f09SDavid van Moolenbroek /* check return code? */
674*00b67f09SDavid van Moolenbroek (void)isc_socket_recv(httpd->sock, &r, 1, task,
675*00b67f09SDavid van Moolenbroek isc_httpd_recvdone, httpd);
676*00b67f09SDavid van Moolenbroek goto out;
677*00b67f09SDavid van Moolenbroek } else if (result != ISC_R_SUCCESS) {
678*00b67f09SDavid van Moolenbroek destroy_client(&httpd);
679*00b67f09SDavid van Moolenbroek goto out;
680*00b67f09SDavid van Moolenbroek }
681*00b67f09SDavid van Moolenbroek
682*00b67f09SDavid van Moolenbroek ISC_HTTPD_SETSEND(httpd);
683*00b67f09SDavid van Moolenbroek
684*00b67f09SDavid van Moolenbroek /*
685*00b67f09SDavid van Moolenbroek * XXXMLG Call function here. Provide an add-header function
686*00b67f09SDavid van Moolenbroek * which will append the common headers to a response we generate.
687*00b67f09SDavid van Moolenbroek */
688*00b67f09SDavid van Moolenbroek isc_buffer_initnull(&httpd->bodybuffer);
689*00b67f09SDavid van Moolenbroek isc_time_now(&now);
690*00b67f09SDavid van Moolenbroek isc_time_formathttptimestamp(&now, datebuf, sizeof(datebuf));
691*00b67f09SDavid van Moolenbroek url = ISC_LIST_HEAD(httpd->mgr->urls);
692*00b67f09SDavid van Moolenbroek while (url != NULL) {
693*00b67f09SDavid van Moolenbroek if (strcmp(httpd->url, url->url) == 0)
694*00b67f09SDavid van Moolenbroek break;
695*00b67f09SDavid van Moolenbroek url = ISC_LIST_NEXT(url, link);
696*00b67f09SDavid van Moolenbroek }
697*00b67f09SDavid van Moolenbroek if (url == NULL)
698*00b67f09SDavid van Moolenbroek result = httpd->mgr->render_404(httpd->url, NULL,
699*00b67f09SDavid van Moolenbroek httpd->querystring,
700*00b67f09SDavid van Moolenbroek NULL, NULL,
701*00b67f09SDavid van Moolenbroek &httpd->retcode,
702*00b67f09SDavid van Moolenbroek &httpd->retmsg,
703*00b67f09SDavid van Moolenbroek &httpd->mimetype,
704*00b67f09SDavid van Moolenbroek &httpd->bodybuffer,
705*00b67f09SDavid van Moolenbroek &httpd->freecb,
706*00b67f09SDavid van Moolenbroek &httpd->freecb_arg);
707*00b67f09SDavid van Moolenbroek else
708*00b67f09SDavid van Moolenbroek result = url->action(httpd->url, url,
709*00b67f09SDavid van Moolenbroek httpd->querystring,
710*00b67f09SDavid van Moolenbroek httpd->headers,
711*00b67f09SDavid van Moolenbroek url->action_arg,
712*00b67f09SDavid van Moolenbroek &httpd->retcode, &httpd->retmsg,
713*00b67f09SDavid van Moolenbroek &httpd->mimetype, &httpd->bodybuffer,
714*00b67f09SDavid van Moolenbroek &httpd->freecb, &httpd->freecb_arg);
715*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS) {
716*00b67f09SDavid van Moolenbroek result = httpd->mgr->render_500(httpd->url, url,
717*00b67f09SDavid van Moolenbroek httpd->querystring,
718*00b67f09SDavid van Moolenbroek NULL, NULL,
719*00b67f09SDavid van Moolenbroek &httpd->retcode,
720*00b67f09SDavid van Moolenbroek &httpd->retmsg,
721*00b67f09SDavid van Moolenbroek &httpd->mimetype,
722*00b67f09SDavid van Moolenbroek &httpd->bodybuffer,
723*00b67f09SDavid van Moolenbroek &httpd->freecb,
724*00b67f09SDavid van Moolenbroek &httpd->freecb_arg);
725*00b67f09SDavid van Moolenbroek RUNTIME_CHECK(result == ISC_R_SUCCESS);
726*00b67f09SDavid van Moolenbroek }
727*00b67f09SDavid van Moolenbroek
728*00b67f09SDavid van Moolenbroek isc_httpd_response(httpd);
729*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Content-Type", httpd->mimetype);
730*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Date", datebuf);
731*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Expires", datebuf);
732*00b67f09SDavid van Moolenbroek
733*00b67f09SDavid van Moolenbroek if (url != NULL && url->isstatic) {
734*00b67f09SDavid van Moolenbroek char loadbuf[ISC_FORMATHTTPTIMESTAMP_SIZE];
735*00b67f09SDavid van Moolenbroek isc_time_formathttptimestamp(&url->loadtime,
736*00b67f09SDavid van Moolenbroek loadbuf, sizeof(loadbuf));
737*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Last-Modified", loadbuf);
738*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Cache-Control: public", NULL);
739*00b67f09SDavid van Moolenbroek } else {
740*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Last-Modified", datebuf);
741*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Pragma: no-cache", NULL);
742*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Cache-Control: no-cache", NULL);
743*00b67f09SDavid van Moolenbroek }
744*00b67f09SDavid van Moolenbroek
745*00b67f09SDavid van Moolenbroek isc_httpd_addheader(httpd, "Server: libisc", NULL);
746*00b67f09SDavid van Moolenbroek isc_httpd_addheaderuint(httpd, "Content-Length",
747*00b67f09SDavid van Moolenbroek isc_buffer_usedlength(&httpd->bodybuffer));
748*00b67f09SDavid van Moolenbroek isc_httpd_endheaders(httpd); /* done */
749*00b67f09SDavid van Moolenbroek
750*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(httpd->bufflist, &httpd->headerbuffer, link);
751*00b67f09SDavid van Moolenbroek /*
752*00b67f09SDavid van Moolenbroek * Link the data buffer into our send queue, should we have any data
753*00b67f09SDavid van Moolenbroek * rendered into it. If no data is present, we won't do anything
754*00b67f09SDavid van Moolenbroek * with the buffer.
755*00b67f09SDavid van Moolenbroek */
756*00b67f09SDavid van Moolenbroek if (isc_buffer_length(&httpd->bodybuffer) > 0)
757*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(httpd->bufflist, &httpd->bodybuffer, link);
758*00b67f09SDavid van Moolenbroek
759*00b67f09SDavid van Moolenbroek /* check return code? */
760*00b67f09SDavid van Moolenbroek (void)isc_socket_sendv(httpd->sock, &httpd->bufflist, task,
761*00b67f09SDavid van Moolenbroek isc_httpd_senddone, httpd);
762*00b67f09SDavid van Moolenbroek
763*00b67f09SDavid van Moolenbroek out:
764*00b67f09SDavid van Moolenbroek isc_event_free(&ev);
765*00b67f09SDavid van Moolenbroek EXIT("recv");
766*00b67f09SDavid van Moolenbroek }
767*00b67f09SDavid van Moolenbroek
768*00b67f09SDavid van Moolenbroek void
isc_httpdmgr_shutdown(isc_httpdmgr_t ** httpdmgrp)769*00b67f09SDavid van Moolenbroek isc_httpdmgr_shutdown(isc_httpdmgr_t **httpdmgrp) {
770*00b67f09SDavid van Moolenbroek isc_httpdmgr_t *httpdmgr;
771*00b67f09SDavid van Moolenbroek isc_httpd_t *httpd;
772*00b67f09SDavid van Moolenbroek httpdmgr = *httpdmgrp;
773*00b67f09SDavid van Moolenbroek *httpdmgrp = NULL;
774*00b67f09SDavid van Moolenbroek
775*00b67f09SDavid van Moolenbroek ENTER("isc_httpdmgr_shutdown");
776*00b67f09SDavid van Moolenbroek
777*00b67f09SDavid van Moolenbroek LOCK(&httpdmgr->lock);
778*00b67f09SDavid van Moolenbroek
779*00b67f09SDavid van Moolenbroek MSETSHUTTINGDOWN(httpdmgr);
780*00b67f09SDavid van Moolenbroek
781*00b67f09SDavid van Moolenbroek isc_socket_cancel(httpdmgr->sock, httpdmgr->task, ISC_SOCKCANCEL_ALL);
782*00b67f09SDavid van Moolenbroek
783*00b67f09SDavid van Moolenbroek httpd = ISC_LIST_HEAD(httpdmgr->running);
784*00b67f09SDavid van Moolenbroek while (httpd != NULL) {
785*00b67f09SDavid van Moolenbroek isc_socket_cancel(httpd->sock, httpdmgr->task,
786*00b67f09SDavid van Moolenbroek ISC_SOCKCANCEL_ALL);
787*00b67f09SDavid van Moolenbroek httpd = ISC_LIST_NEXT(httpd, link);
788*00b67f09SDavid van Moolenbroek }
789*00b67f09SDavid van Moolenbroek
790*00b67f09SDavid van Moolenbroek UNLOCK(&httpdmgr->lock);
791*00b67f09SDavid van Moolenbroek
792*00b67f09SDavid van Moolenbroek EXIT("isc_httpdmgr_shutdown");
793*00b67f09SDavid van Moolenbroek }
794*00b67f09SDavid van Moolenbroek
795*00b67f09SDavid van Moolenbroek static isc_result_t
grow_headerspace(isc_httpd_t * httpd)796*00b67f09SDavid van Moolenbroek grow_headerspace(isc_httpd_t *httpd) {
797*00b67f09SDavid van Moolenbroek char *newspace;
798*00b67f09SDavid van Moolenbroek unsigned int newlen;
799*00b67f09SDavid van Moolenbroek isc_region_t r;
800*00b67f09SDavid van Moolenbroek
801*00b67f09SDavid van Moolenbroek newlen = httpd->headerlen + HTTP_SENDGROW;
802*00b67f09SDavid van Moolenbroek if (newlen > HTTP_SEND_MAXLEN)
803*00b67f09SDavid van Moolenbroek return (ISC_R_NOSPACE);
804*00b67f09SDavid van Moolenbroek
805*00b67f09SDavid van Moolenbroek newspace = isc_mem_get(httpd->mgr->mctx, newlen);
806*00b67f09SDavid van Moolenbroek if (newspace == NULL)
807*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
808*00b67f09SDavid van Moolenbroek isc_buffer_region(&httpd->headerbuffer, &r);
809*00b67f09SDavid van Moolenbroek isc_buffer_reinit(&httpd->headerbuffer, newspace, newlen);
810*00b67f09SDavid van Moolenbroek
811*00b67f09SDavid van Moolenbroek isc_mem_put(httpd->mgr->mctx, r.base, r.length);
812*00b67f09SDavid van Moolenbroek
813*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
814*00b67f09SDavid van Moolenbroek }
815*00b67f09SDavid van Moolenbroek
816*00b67f09SDavid van Moolenbroek isc_result_t
isc_httpd_response(isc_httpd_t * httpd)817*00b67f09SDavid van Moolenbroek isc_httpd_response(isc_httpd_t *httpd) {
818*00b67f09SDavid van Moolenbroek isc_result_t result;
819*00b67f09SDavid van Moolenbroek unsigned int needlen;
820*00b67f09SDavid van Moolenbroek
821*00b67f09SDavid van Moolenbroek needlen = strlen(httpd->protocol) + 1; /* protocol + space */
822*00b67f09SDavid van Moolenbroek needlen += 3 + 1; /* room for response code, always 3 bytes */
823*00b67f09SDavid van Moolenbroek needlen += strlen(httpd->retmsg) + 2; /* return msg + CRLF */
824*00b67f09SDavid van Moolenbroek
825*00b67f09SDavid van Moolenbroek while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
826*00b67f09SDavid van Moolenbroek result = grow_headerspace(httpd);
827*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
828*00b67f09SDavid van Moolenbroek return (result);
829*00b67f09SDavid van Moolenbroek }
830*00b67f09SDavid van Moolenbroek
831*00b67f09SDavid van Moolenbroek sprintf(isc_buffer_used(&httpd->headerbuffer), "%s %03d %s\r\n",
832*00b67f09SDavid van Moolenbroek httpd->protocol, httpd->retcode, httpd->retmsg);
833*00b67f09SDavid van Moolenbroek isc_buffer_add(&httpd->headerbuffer, needlen);
834*00b67f09SDavid van Moolenbroek
835*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
836*00b67f09SDavid van Moolenbroek }
837*00b67f09SDavid van Moolenbroek
838*00b67f09SDavid van Moolenbroek isc_result_t
isc_httpd_addheader(isc_httpd_t * httpd,const char * name,const char * val)839*00b67f09SDavid van Moolenbroek isc_httpd_addheader(isc_httpd_t *httpd, const char *name,
840*00b67f09SDavid van Moolenbroek const char *val)
841*00b67f09SDavid van Moolenbroek {
842*00b67f09SDavid van Moolenbroek isc_result_t result;
843*00b67f09SDavid van Moolenbroek unsigned int needlen;
844*00b67f09SDavid van Moolenbroek
845*00b67f09SDavid van Moolenbroek needlen = strlen(name); /* name itself */
846*00b67f09SDavid van Moolenbroek if (val != NULL)
847*00b67f09SDavid van Moolenbroek needlen += 2 + strlen(val); /* :<space> and val */
848*00b67f09SDavid van Moolenbroek needlen += 2; /* CRLF */
849*00b67f09SDavid van Moolenbroek
850*00b67f09SDavid van Moolenbroek while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
851*00b67f09SDavid van Moolenbroek result = grow_headerspace(httpd);
852*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
853*00b67f09SDavid van Moolenbroek return (result);
854*00b67f09SDavid van Moolenbroek }
855*00b67f09SDavid van Moolenbroek
856*00b67f09SDavid van Moolenbroek if (val != NULL)
857*00b67f09SDavid van Moolenbroek sprintf(isc_buffer_used(&httpd->headerbuffer),
858*00b67f09SDavid van Moolenbroek "%s: %s\r\n", name, val);
859*00b67f09SDavid van Moolenbroek else
860*00b67f09SDavid van Moolenbroek sprintf(isc_buffer_used(&httpd->headerbuffer),
861*00b67f09SDavid van Moolenbroek "%s\r\n", name);
862*00b67f09SDavid van Moolenbroek
863*00b67f09SDavid van Moolenbroek isc_buffer_add(&httpd->headerbuffer, needlen);
864*00b67f09SDavid van Moolenbroek
865*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
866*00b67f09SDavid van Moolenbroek }
867*00b67f09SDavid van Moolenbroek
868*00b67f09SDavid van Moolenbroek isc_result_t
isc_httpd_endheaders(isc_httpd_t * httpd)869*00b67f09SDavid van Moolenbroek isc_httpd_endheaders(isc_httpd_t *httpd) {
870*00b67f09SDavid van Moolenbroek isc_result_t result;
871*00b67f09SDavid van Moolenbroek
872*00b67f09SDavid van Moolenbroek while (isc_buffer_availablelength(&httpd->headerbuffer) < 2) {
873*00b67f09SDavid van Moolenbroek result = grow_headerspace(httpd);
874*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
875*00b67f09SDavid van Moolenbroek return (result);
876*00b67f09SDavid van Moolenbroek }
877*00b67f09SDavid van Moolenbroek
878*00b67f09SDavid van Moolenbroek sprintf(isc_buffer_used(&httpd->headerbuffer), "\r\n");
879*00b67f09SDavid van Moolenbroek isc_buffer_add(&httpd->headerbuffer, 2);
880*00b67f09SDavid van Moolenbroek
881*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
882*00b67f09SDavid van Moolenbroek }
883*00b67f09SDavid van Moolenbroek
884*00b67f09SDavid van Moolenbroek isc_result_t
isc_httpd_addheaderuint(isc_httpd_t * httpd,const char * name,int val)885*00b67f09SDavid van Moolenbroek isc_httpd_addheaderuint(isc_httpd_t *httpd, const char *name, int val) {
886*00b67f09SDavid van Moolenbroek isc_result_t result;
887*00b67f09SDavid van Moolenbroek unsigned int needlen;
888*00b67f09SDavid van Moolenbroek char buf[sizeof "18446744073709551616"];
889*00b67f09SDavid van Moolenbroek
890*00b67f09SDavid van Moolenbroek sprintf(buf, "%d", val);
891*00b67f09SDavid van Moolenbroek
892*00b67f09SDavid van Moolenbroek needlen = strlen(name); /* name itself */
893*00b67f09SDavid van Moolenbroek needlen += 2 + strlen(buf); /* :<space> and val */
894*00b67f09SDavid van Moolenbroek needlen += 2; /* CRLF */
895*00b67f09SDavid van Moolenbroek
896*00b67f09SDavid van Moolenbroek while (isc_buffer_availablelength(&httpd->headerbuffer) < needlen) {
897*00b67f09SDavid van Moolenbroek result = grow_headerspace(httpd);
898*00b67f09SDavid van Moolenbroek if (result != ISC_R_SUCCESS)
899*00b67f09SDavid van Moolenbroek return (result);
900*00b67f09SDavid van Moolenbroek }
901*00b67f09SDavid van Moolenbroek
902*00b67f09SDavid van Moolenbroek sprintf(isc_buffer_used(&httpd->headerbuffer),
903*00b67f09SDavid van Moolenbroek "%s: %s\r\n", name, buf);
904*00b67f09SDavid van Moolenbroek
905*00b67f09SDavid van Moolenbroek isc_buffer_add(&httpd->headerbuffer, needlen);
906*00b67f09SDavid van Moolenbroek
907*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
908*00b67f09SDavid van Moolenbroek }
909*00b67f09SDavid van Moolenbroek
910*00b67f09SDavid van Moolenbroek static void
isc_httpd_senddone(isc_task_t * task,isc_event_t * ev)911*00b67f09SDavid van Moolenbroek isc_httpd_senddone(isc_task_t *task, isc_event_t *ev) {
912*00b67f09SDavid van Moolenbroek isc_httpd_t *httpd = ev->ev_arg;
913*00b67f09SDavid van Moolenbroek isc_region_t r;
914*00b67f09SDavid van Moolenbroek isc_socketevent_t *sev = (isc_socketevent_t *)ev;
915*00b67f09SDavid van Moolenbroek
916*00b67f09SDavid van Moolenbroek ENTER("senddone");
917*00b67f09SDavid van Moolenbroek INSIST(ISC_HTTPD_ISSEND(httpd));
918*00b67f09SDavid van Moolenbroek
919*00b67f09SDavid van Moolenbroek /*
920*00b67f09SDavid van Moolenbroek * First, unlink our header buffer from the socket's bufflist. This
921*00b67f09SDavid van Moolenbroek * is sort of an evil hack, since we know our buffer will be there,
922*00b67f09SDavid van Moolenbroek * and we know it's address, so we can just remove it directly.
923*00b67f09SDavid van Moolenbroek */
924*00b67f09SDavid van Moolenbroek NOTICE("senddone unlinked header");
925*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(sev->bufferlist, &httpd->headerbuffer, link);
926*00b67f09SDavid van Moolenbroek
927*00b67f09SDavid van Moolenbroek /*
928*00b67f09SDavid van Moolenbroek * We will always want to clean up our receive buffer, even if we
929*00b67f09SDavid van Moolenbroek * got an error on send or we are shutting down.
930*00b67f09SDavid van Moolenbroek *
931*00b67f09SDavid van Moolenbroek * We will pass in the buffer only if there is data in it. If
932*00b67f09SDavid van Moolenbroek * there is no data, we will pass in a NULL.
933*00b67f09SDavid van Moolenbroek */
934*00b67f09SDavid van Moolenbroek if (httpd->freecb != NULL) {
935*00b67f09SDavid van Moolenbroek isc_buffer_t *b = NULL;
936*00b67f09SDavid van Moolenbroek if (isc_buffer_length(&httpd->bodybuffer) > 0) {
937*00b67f09SDavid van Moolenbroek b = &httpd->bodybuffer;
938*00b67f09SDavid van Moolenbroek httpd->freecb(b, httpd->freecb_arg);
939*00b67f09SDavid van Moolenbroek }
940*00b67f09SDavid van Moolenbroek NOTICE("senddone free callback performed");
941*00b67f09SDavid van Moolenbroek }
942*00b67f09SDavid van Moolenbroek if (ISC_LINK_LINKED(&httpd->bodybuffer, link)) {
943*00b67f09SDavid van Moolenbroek ISC_LIST_UNLINK(sev->bufferlist, &httpd->bodybuffer, link);
944*00b67f09SDavid van Moolenbroek NOTICE("senddone body buffer unlinked");
945*00b67f09SDavid van Moolenbroek }
946*00b67f09SDavid van Moolenbroek
947*00b67f09SDavid van Moolenbroek if (sev->result != ISC_R_SUCCESS) {
948*00b67f09SDavid van Moolenbroek destroy_client(&httpd);
949*00b67f09SDavid van Moolenbroek goto out;
950*00b67f09SDavid van Moolenbroek }
951*00b67f09SDavid van Moolenbroek
952*00b67f09SDavid van Moolenbroek if ((httpd->flags & HTTPD_CLOSE) != 0) {
953*00b67f09SDavid van Moolenbroek destroy_client(&httpd);
954*00b67f09SDavid van Moolenbroek goto out;
955*00b67f09SDavid van Moolenbroek }
956*00b67f09SDavid van Moolenbroek
957*00b67f09SDavid van Moolenbroek ISC_HTTPD_SETRECV(httpd);
958*00b67f09SDavid van Moolenbroek
959*00b67f09SDavid van Moolenbroek NOTICE("senddone restarting recv on socket");
960*00b67f09SDavid van Moolenbroek
961*00b67f09SDavid van Moolenbroek reset_client(httpd);
962*00b67f09SDavid van Moolenbroek
963*00b67f09SDavid van Moolenbroek r.base = (unsigned char *)httpd->recvbuf;
964*00b67f09SDavid van Moolenbroek r.length = HTTP_RECVLEN - 1;
965*00b67f09SDavid van Moolenbroek /* check return code? */
966*00b67f09SDavid van Moolenbroek (void)isc_socket_recv(httpd->sock, &r, 1, task,
967*00b67f09SDavid van Moolenbroek isc_httpd_recvdone, httpd);
968*00b67f09SDavid van Moolenbroek
969*00b67f09SDavid van Moolenbroek out:
970*00b67f09SDavid van Moolenbroek isc_event_free(&ev);
971*00b67f09SDavid van Moolenbroek EXIT("senddone");
972*00b67f09SDavid van Moolenbroek }
973*00b67f09SDavid van Moolenbroek
974*00b67f09SDavid van Moolenbroek static void
reset_client(isc_httpd_t * httpd)975*00b67f09SDavid van Moolenbroek reset_client(isc_httpd_t *httpd) {
976*00b67f09SDavid van Moolenbroek /*
977*00b67f09SDavid van Moolenbroek * Catch errors here. We MUST be in RECV mode, and we MUST NOT have
978*00b67f09SDavid van Moolenbroek * any outstanding buffers. If we have buffers, we have a leak.
979*00b67f09SDavid van Moolenbroek */
980*00b67f09SDavid van Moolenbroek INSIST(ISC_HTTPD_ISRECV(httpd));
981*00b67f09SDavid van Moolenbroek INSIST(!ISC_LINK_LINKED(&httpd->headerbuffer, link));
982*00b67f09SDavid van Moolenbroek INSIST(!ISC_LINK_LINKED(&httpd->bodybuffer, link));
983*00b67f09SDavid van Moolenbroek
984*00b67f09SDavid van Moolenbroek httpd->recvbuf[0] = 0;
985*00b67f09SDavid van Moolenbroek httpd->recvlen = 0;
986*00b67f09SDavid van Moolenbroek httpd->headers = NULL;
987*00b67f09SDavid van Moolenbroek httpd->method = ISC_HTTPD_METHODUNKNOWN;
988*00b67f09SDavid van Moolenbroek httpd->url = NULL;
989*00b67f09SDavid van Moolenbroek httpd->querystring = NULL;
990*00b67f09SDavid van Moolenbroek httpd->protocol = NULL;
991*00b67f09SDavid van Moolenbroek httpd->flags = 0;
992*00b67f09SDavid van Moolenbroek
993*00b67f09SDavid van Moolenbroek isc_buffer_clear(&httpd->headerbuffer);
994*00b67f09SDavid van Moolenbroek isc_buffer_invalidate(&httpd->bodybuffer);
995*00b67f09SDavid van Moolenbroek }
996*00b67f09SDavid van Moolenbroek
997*00b67f09SDavid van Moolenbroek isc_result_t
isc_httpdmgr_addurl(isc_httpdmgr_t * httpdmgr,const char * url,isc_httpdaction_t * func,void * arg)998*00b67f09SDavid van Moolenbroek isc_httpdmgr_addurl(isc_httpdmgr_t *httpdmgr, const char *url,
999*00b67f09SDavid van Moolenbroek isc_httpdaction_t *func, void *arg)
1000*00b67f09SDavid van Moolenbroek {
1001*00b67f09SDavid van Moolenbroek return (isc_httpdmgr_addurl2(httpdmgr, url, ISC_FALSE, func, arg));
1002*00b67f09SDavid van Moolenbroek }
1003*00b67f09SDavid van Moolenbroek
1004*00b67f09SDavid van Moolenbroek isc_result_t
isc_httpdmgr_addurl2(isc_httpdmgr_t * httpdmgr,const char * url,isc_boolean_t isstatic,isc_httpdaction_t * func,void * arg)1005*00b67f09SDavid van Moolenbroek isc_httpdmgr_addurl2(isc_httpdmgr_t *httpdmgr, const char *url,
1006*00b67f09SDavid van Moolenbroek isc_boolean_t isstatic,
1007*00b67f09SDavid van Moolenbroek isc_httpdaction_t *func, void *arg)
1008*00b67f09SDavid van Moolenbroek {
1009*00b67f09SDavid van Moolenbroek isc_httpdurl_t *item;
1010*00b67f09SDavid van Moolenbroek
1011*00b67f09SDavid van Moolenbroek if (url == NULL) {
1012*00b67f09SDavid van Moolenbroek httpdmgr->render_404 = func;
1013*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1014*00b67f09SDavid van Moolenbroek }
1015*00b67f09SDavid van Moolenbroek
1016*00b67f09SDavid van Moolenbroek item = isc_mem_get(httpdmgr->mctx, sizeof(isc_httpdurl_t));
1017*00b67f09SDavid van Moolenbroek if (item == NULL)
1018*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
1019*00b67f09SDavid van Moolenbroek
1020*00b67f09SDavid van Moolenbroek item->url = isc_mem_strdup(httpdmgr->mctx, url);
1021*00b67f09SDavid van Moolenbroek if (item->url == NULL) {
1022*00b67f09SDavid van Moolenbroek isc_mem_put(httpdmgr->mctx, item, sizeof(isc_httpdurl_t));
1023*00b67f09SDavid van Moolenbroek return (ISC_R_NOMEMORY);
1024*00b67f09SDavid van Moolenbroek }
1025*00b67f09SDavid van Moolenbroek
1026*00b67f09SDavid van Moolenbroek item->action = func;
1027*00b67f09SDavid van Moolenbroek item->action_arg = arg;
1028*00b67f09SDavid van Moolenbroek item->isstatic = isstatic;
1029*00b67f09SDavid van Moolenbroek isc_time_now(&item->loadtime);
1030*00b67f09SDavid van Moolenbroek
1031*00b67f09SDavid van Moolenbroek ISC_LINK_INIT(item, link);
1032*00b67f09SDavid van Moolenbroek ISC_LIST_APPEND(httpdmgr->urls, item, link);
1033*00b67f09SDavid van Moolenbroek
1034*00b67f09SDavid van Moolenbroek return (ISC_R_SUCCESS);
1035*00b67f09SDavid van Moolenbroek }
1036