xref: /minix3/external/bsd/bind/dist/lib/isc/httpd.c (revision 00b67f09dd46474d133c95011a48590a8e8f94c7)
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