1 /*
2    HTTP Request Handling
3    Copyright (C) 1999-2002, Joe Orton <joe@manyfish.co.uk>
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14 
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
18    MA 02111-1307, USA
19 
20 */
21 
22 #ifndef NE_REQUEST_H
23 #define NE_REQUEST_H
24 
25 #include "ne_utils.h" /* For ne_status */
26 #include "ne_string.h" /* For ne_buffer */
27 #include "ne_session.h"
28 
29 BEGIN_NEON_DECLS
30 
31 #define NE_OK (0) /* Success */
32 #define NE_ERROR (1) /* Generic error; use ne_get_error(session) for message */
33 #define NE_LOOKUP (2) /* Server or proxy hostname lookup failed */
34 #define NE_AUTH (3) /* User authentication failed on server */
35 #define NE_PROXYAUTH (4) /* User authentication failed on proxy */
36 #define NE_CONNECT (5) /* Could not connect to server */
37 #define NE_TIMEOUT (6) /* Connection timed out */
38 #define NE_FAILED (7) /* The precondition failed */
39 #define NE_RETRY (8) /* Retry request (ne_end_request ONLY) */
40 #define NE_REDIRECT (9) /* See ne_redirect.h */
41 
42 /* FIXME: remove this */
43 #define EOL "\r\n"
44 
45 /* Opaque object representing a single HTTP request. */
46 typedef struct ne_request_s ne_request;
47 
48 /***** Request Handling *****/
49 
50 /* Create a request in session 'sess', with given method and path.
51  * 'path' must conform to the 'abs_path' grammar in RFC2396, with an
52  * optional "? query" part, and MUST be URI-escaped by the caller. */
53 ne_request *ne_request_create(ne_session *sess,
54 			      const char *method, const char *path);
55 
56 /* 'buffer' will be sent as the request body with given request. */
57 void ne_set_request_body_buffer(ne_request *req, const char *buffer,
58 				size_t size);
59 
60 /* Send the contents of a file as the request body; 'fd' must be a
61  * file descriptor of an open, seekable file.  Current file offset of
62  * fd is not retained (and ignored: the file is read from the the
63  * first byte). Returns:
64  *  0 on okay.
65  *  non-zero if could not determine length of file.  */
66 int ne_set_request_body_fd(ne_request *req, int fd);
67 
68 /* "Pull"-based request body provider: a callback which is invoked to
69  * provide blocks of request body on demand.
70  *
71  * Before each time the body is provided, the callback will be called
72  * once with buflen == 0.  The body may have to be provided >1 time
73  * per request (for authentication retries etc.).
74  *
75  * The callback must return:
76  *        <0           : error, abort request.
77  *         0           : ignore 'buffer' contents, end of body.
78  *     0 < x <= buflen : buffer contains x bytes of body data.  */
79 typedef ssize_t (*ne_provide_body)(void *userdata,
80 				   char *buffer, size_t buflen);
81 
82 /* Install a callback which is invoked as needed to provide request
83  * body blocks.  Total request body is 'size' bytes: the callback MUST
84  * ensure it returns in total exactly 'size' bytes each time the
85  * request body is provided. */
86 void ne_set_request_body_provider(ne_request *req, size_t size,
87 				  ne_provide_body provider, void *userdata);
88 
89 /* Handling response bodies... you provide TWO callbacks:
90  *
91  * 1) 'acceptance' callback: determines whether you want to handle the
92  * response body given the response-status information, e.g., if you
93  * only want 2xx responses, say so here.
94  *
95  * 2) 'reader' callback: passed blocks of the response-body as they
96  * arrive, if the acceptance callback returned non-zero.  */
97 
98 /* 'acceptance' callback type. Return non-zero to accept the response,
99  * else zero to ignore it. */
100 typedef int (*ne_accept_response)(
101     void *userdata, ne_request *req, const ne_status *st);
102 
103 /* An 'acceptance' callback which only accepts 2xx-class responses.
104  * Ignores userdata. */
105 int ne_accept_2xx(void *userdata, ne_request *req, const ne_status *st);
106 
107 /* An acceptance callback which accepts all responses.  Ignores
108  * userdata. */
109 int ne_accept_always(void *userdata, ne_request *req, const ne_status *st);
110 
111 /* Callback for reading a block of data. */
112 typedef void (*ne_block_reader)(void *userdata, const char *buf, size_t len);
113 
114 /* Add a response reader for the given request, with the given
115  * acceptance function. userdata is passed as the first argument to
116  * the acceptance + reader callbacks.
117  *
118  * The acceptance callback is called once each time the request is
119  * sent: it may be sent >1 time because of authentication retries etc.
120  * For each time the acceptance callback is called, if it returns
121  * non-zero, blocks of the response body will be passed to the reader
122  * callback as the response is read.  After all the response body has
123  * been read, the callback will be called with a 'len' argument of
124  * zero.  */
125 void ne_add_response_body_reader(ne_request *req, ne_accept_response accpt,
126 				 ne_block_reader reader, void *userdata);
127 
128 /* Handle response headers. Each handler is associated with a specific
129  * header field (indicated by name). The handler is then passed the
130  * value of this header field. */
131 
132 /* The header handler callback type */
133 typedef void (*ne_header_handler)(void *userdata, const char *value);
134 
135 /* Adds a response header handler for the given request. userdata is passed
136  * as the first argument to the header handler, and the 'value' is the
137  * header field value (i.e. doesn't include the "Header-Name: " part").
138  */
139 void ne_add_response_header_handler(ne_request *req, const char *name,
140 				    ne_header_handler hdl, void *userdata);
141 
142 /* Add handler which is passed ALL header values regardless of name */
143 void ne_add_response_header_catcher(ne_request *req,
144 				    ne_header_handler hdl, void *userdata);
145 
146 /* Stock header handlers:
147  *  'duplicate': *(char **)userdata = strdup(value)
148  *  'numeric':   *(int *)userdata = atoi(value)
149  * e.g.
150  *   int mynum;
151  *   ne_add_response_header_handler(myreq, "Content-Length",
152  *                                    ne_handle_numeric_handler, &mynum);
153  * ... arranges mynum to be set to the value of the Content-Length header.
154  */
155 void ne_duplicate_header(void *userdata, const char *value);
156 void ne_handle_numeric_header(void *userdata, const char *value);
157 
158 /* Adds a header to the request with given name and value. */
159 void ne_add_request_header(ne_request *req, const char *name,
160 			   const char *value);
161 /* Adds a header to the request with given name, using printf-like
162  * format arguments for the value. */
163 void ne_print_request_header(ne_request *req, const char *name,
164 			     const char *format, ...)
165     ne_attribute((format(printf, 3, 4)));
166 
167 /* ne_request_dispatch: Sends the given request, and reads the
168  * response. Response-Status information can be retrieve with
169  * ne_get_status(req).
170  *
171  *  NE_OK         if request sent + response read okay.
172  *  NE_AUTH       user not authorised on server
173  *  NE_PROXYAUTH  user not authorised on proxy server
174  *  NE_CONNECT    could not connect to server/proxy server
175  *  NE_TIMEOUT    connection timed out mid-request
176  *  NE_ERROR      for other errors, and ne_get_error() should
177  *                  return a meaningful error string
178  */
179 int ne_request_dispatch(ne_request *req);
180 
181 /* Returns a pointer to the response status information for the given
182  * request; pointer is valid until request object is destroyed. */
183 const ne_status *ne_get_status(const ne_request *req) ne_attribute((const));
184 
185 /* Returns pointer to session associated with request. */
186 ne_session *ne_get_session(const ne_request *req);
187 
188 /* Destroy memory associated with request pointer */
189 void ne_request_destroy(ne_request *req);
190 
191 /* "Caller-pulls" request interface.  This is an ALTERNATIVE interface
192  * to ne_request_dispatch: either use that, or do all this yourself:
193  *
194  * caller must call:
195  *  1. ne_begin_request (fail if returns non-NE_OK)
196  *  2. while(ne_read_response_block(...) > 0) ... loop ...;
197  *     (fail if ne_read_response_block returns <0)
198  *  3. ne_end_request
199  *
200  * ne_end_request and ne_begin_request both return an NE_* code; if
201  * ne_end_request returns NE_RETRY, you must restart the loop from (1)
202  * above. */
203 int ne_begin_request(ne_request *req);
204 int ne_end_request(ne_request *req);
205 
206 /* Read a block of the response.  buffer must be at least 128 bytes.
207  * 'buflen' must be length of buffer.
208  *
209  * Returns:
210  *  <0 - error, stop reading.
211  *   0 - end of response
212  *  >0 - number of bytes read into buffer.
213  */
214 ssize_t ne_read_response_block(ne_request *req, char *buffer, size_t buflen);
215 
216 /**** Request hooks handling *****/
217 
218 typedef void (*ne_free_hooks)(void *cookie);
219 
220 /* Hook called when a create is created; passed the request method,
221  * and the string used as the Request-URI (which may be an abs_path,
222  * or an absoluteURI, depending on whether an HTTP proxy is in
223  * use).  */
224 typedef void (*ne_create_request_fn)(ne_request *req, void *userdata,
225 				     const char *method, const char *requri);
226 void ne_hook_create_request(ne_session *sess,
227 			    ne_create_request_fn fn, void *userdata);
228 
229 /* Hook called before the request is sent.  'header' is the raw HTTP
230  * header before the trailing CRLF is added: add in more here. */
231 typedef void (*ne_pre_send_fn)(ne_request *req, void *userdata,
232 			       ne_buffer *header);
233 void ne_hook_pre_send(ne_session *sess, ne_pre_send_fn fn, void *userdata);
234 
235 /* Hook called after the request is sent. May return:
236  *  NE_OK     everything is okay
237  *  NE_RETRY  try sending the request again.
238  * anything else signifies an error, and the request is failed. The return
239  * code is passed back the _dispatch caller, so the session error must
240  * also be set appropriately (ne_set_error).
241  */
242 typedef int (*ne_post_send_fn)(ne_request *req, void *userdata,
243 			       const ne_status *status);
244 void ne_hook_post_send(ne_session *sess, ne_post_send_fn fn, void *userdata);
245 
246 /* Hook called when the function is destroyed. */
247 typedef void (*ne_destroy_req_fn)(ne_request *req, void *userdata);
248 void ne_hook_destroy_request(ne_session *sess,
249 			     ne_destroy_req_fn fn, void *userdata);
250 
251 typedef void (*ne_destroy_sess_fn)(void *userdata);
252 /* Hook called when the session is destroyed. */
253 void ne_hook_destroy_session(ne_session *sess,
254 			     ne_destroy_sess_fn fn, void *userdata);
255 
256 /* Store an opaque context for the request, 'priv' is returned by a
257  * call to ne_request_get_private with the same ID. */
258 void ne_set_request_private(ne_request *req, const char *id, void *priv);
259 void *ne_get_request_private(ne_request *req, const char *id);
260 
261 END_NEON_DECLS
262 
263 #endif /* NE_REQUEST_H */
264 
265