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