Back to index

avfs  1.0.1
http_request.h
Go to the documentation of this file.
00001 /* 
00002    HTTP Request Handling
00003    Copyright (C) 1999-2001, Joe Orton <joe@light.plus.com>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009    
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public
00016    License along with this library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00018    MA 02111-1307, USA
00019 
00020 */
00021 
00022 #ifndef HTTP_REQUEST_H
00023 #define HTTP_REQUEST_H
00024 
00025 #include <stdio.h> /* For FILE * */
00026 
00027 #include "http_utils.h" /* For http_status */
00028 #include "string_utils.h" /* For sbuffer */
00029 #include "nsocket.h" /* for nssl_context */
00030 
00031 BEGIN_NEON_DECLS
00032 
00033 #define HTTP_OK (0)
00034 #define HTTP_ERROR (1) /* Generic error; use http_get_error(session) for message */
00035 #define HTTP_LOOKUP (3) /* Name lookup failed */
00036 #define HTTP_AUTH (4) /* User authentication failed on server */
00037 #define HTTP_AUTHPROXY (5) /* User authentication failed on proxy */
00038 #define HTTP_SERVERAUTH (6) /* Server authentication failed */
00039 #define HTTP_PROXYAUTH (7) /* Proxy authentication failed */
00040 #define HTTP_CONNECT (8) /* Could not connect to server */
00041 #define HTTP_TIMEOUT (9) /* Connection timed out */
00042 #define HTTP_FAILED (10) /* The precondition failed */
00043 
00044 /* Internal use only */
00045 #define HTTP_RETRY (101)
00046 
00047 #define EOL "\r\n"
00048 
00049 /****** Session Handling ******/
00050 
00051 typedef struct http_session_s http_session;
00052 typedef struct http_req_s http_req;
00053 
00054 /* 
00055  * Session handling:
00056  *  Call order:
00057  *  0.   sock_init             MANDATORY
00058  *  1.   http_session_create   MANDATORY
00059  *  2.   http_session_proxy    OPTIONAL
00060  *  3.   http_session_server   MANDATORY
00061  *  4.   http_set_*            OPTIONAL
00062  *  ...  --- Any HTTP request method ---
00063  *  n.   http_session_destroy  MANDATORY
00064  */
00065  
00066 /* Create a new HTTP session */
00067 http_session *http_session_create(void);
00068 
00069 /* Finish an HTTP session */
00070 int http_session_destroy(http_session *sess);
00071 
00072 /* Set the server or proxy server to be used for the session.
00073  * Returns:
00074  *   HTTP_LOOKUP if the DNS lookup for hostname failed.
00075  *   HTTP_OK otherwise.
00076  *
00077  * Note that if a proxy is being used, http_session_proxy should be
00078  * called BEFORE http_session_server, so the DNS lookup can be skipped
00079  * on the server. */
00080 int http_session_server(http_session *sess, const char *hostname, int port);
00081 int http_session_proxy(http_session *sess, const char *hostname, int port);
00082 
00083 /* Callback to determine whether the proxy server should be used or
00084  * not for a request to the given hostname using the given scheme.
00085  * Scheme will be "http" or "https" etc.
00086  * Must return:
00087  *   Zero to indicate the proxy should NOT be used
00088  *   Non-zero to indicate the proxy SHOULD be used.
00089  */
00090 typedef int (*http_use_proxy)(void *userdata,
00091                            const char *scheme, const char *hostname);
00092 
00093 /* Register the callback for determining whether the proxy server
00094  * should be used or not here.  'userdata' will be passed as the first
00095  * argument to the callback. The callback is only called if a proxy
00096  * server has been set up using http_session_proxy. 
00097  *
00098  * This function MUST be called before calling http_session_server.
00099  */
00100 void http_session_decide_proxy(http_session *sess, http_use_proxy use_proxy,
00101                             void *userdata);
00102 
00103 /* Set protocol options for session:
00104  *   expect100: Defaults to OFF
00105  *   persist:   Defaults to ON
00106  *
00107  * expect100: When set, send the "Expect: 100-continue" request header
00108  * with requests with bodies.
00109  *
00110  * persist: When set, use a persistent connection. (Generally,
00111  * you don't want to turn this off.)
00112  * */
00113 void http_set_expect100(http_session *sess, int use_expect100);
00114 void http_set_persist(http_session *sess, int persist);
00115 
00116 /* Using SSL/TLS connections:
00117  *
00118  * Session settings:
00119  *   secure:                 Defaults to OFF
00120  *   secure_context:         No callbacks, any protocol allowed.
00121  *   request_secure_upgrade: Defaults to OFF
00122  *   accept_secure_ugprade:  Defaults to OFF
00123  *
00124  * secure_context: When set, specifies the settings to use for secure
00125  * connections, and any callbacks (see nsocket.h).  The lifetime of
00126  * the context object must be >= to the lifetime of the session
00127  * object.
00128  *
00129  * secure: When set, use a secure (SSL/TLS) connection to the origin
00130  * server. This will tunnel (using CONNECT) through the proxy server
00131  * if one is being used.
00132  *
00133  * request_secure_upgrade: When set, notify the server with each
00134  * request made that an upgrade to a secure connection is desired, if
00135  * available.
00136  *
00137  * accept_secure_upgrade: When set, allow a server-requested upgrade
00138  * to a secure connection.
00139  *
00140  * NB: the latter three function calls will return -1 if SSL is not
00141  * supported by the library (i.e., it was not built against OpenSSL),
00142  * or 0 if it is.
00143  * */
00144 void http_set_secure_context(http_session *sess, nssl_context *ctx);
00145 int http_set_secure(http_session *sess, int secure);
00146 int http_set_request_secure_upgrade(http_session *sess, int req_upgrade);
00147 int http_set_accept_secure_upgrade(http_session *sess, int acc_upgrade);
00148 
00149 /* Sets the user-agent string. neon/VERSION will be appended, to make
00150  * the full header "User-Agent: product neon/VERSION".
00151  * If this function is not called, the User-Agent header is not sent.
00152  * The product string must follow the RFC2616 format, i.e.
00153  *       product         = token ["/" product-version]
00154  *       product-version = token
00155  * where token is any alpha-numeric-y string [a-zA-Z0-9]*
00156  */
00157 void http_set_useragent(http_session *sess, const char *product);
00158 
00159 /* Determine if next-hop server claims HTTP/1.1 compliance. Returns:
00160  *   0 if next-hop server does NOT claim HTTP/1.1 compliance
00161  *   non-zero if next-hop server DOES claim HTTP/1.1 compliance
00162  * Not that the "next-hop" server is the proxy server if one is being
00163  * used, otherwise, the origin server.
00164  */
00165 int http_version_pre_http11(http_session *sess);
00166 
00167 /* Returns the 'hostport' URI segment for the end-server, e.g.
00168  *    "my.server.com:8080"    or    "www.server.com" 
00169  *  (port segment is ommitted if == 80) 
00170  */
00171 const char *http_get_server_hostport(http_session *sess);
00172 
00173 /* Returns the URL scheme being used for the current session.
00174  * Does NOT include a trailing ':'. 
00175  * Example returns: "http" or "https".
00176  */
00177 const char *http_get_scheme(http_session *sess);
00178 
00179 #if 0 /* TODO: implement */
00180 typedef int (*http_request_redirect)(void *userdata, 
00181                                  int code, const char *reason,
00182                                  const char *from_uri, const char *to_uri);
00183 
00184 void http_set_redirect_handler(http_session *sess, 
00185                             http_request_redirect hdlr, void *userdata); 
00186 #endif
00187 
00188 /* The callback used to request the username and password in the given
00189  * realm. The username and password must be placed in malloc()-allocated
00190  * memory.
00191  * Must return:
00192  *   0 on success: *username and *password must be non-NULL, and will
00193  *                 be free'd by the HTTP layer when necessary
00194  *  -1 to cancel (*username and *password are ignored.)
00195  */
00196 typedef int (*http_request_auth)(
00197     void *userdata, const char *realm, const char *hostname,
00198     char **username, char **password);
00199 
00200 /* Set callbacks to handle server and proxy authentication.
00201  * userdata is passed as the first argument to the callback. */
00202 void http_set_server_auth(http_session *sess, http_request_auth callback, 
00203                        void *userdata);
00204 void http_set_proxy_auth(http_session *sess, http_request_auth callback, 
00205                       void *userdata);
00206 
00207 /* Set the error string for the session */
00208 void http_set_error(http_session *sess, const char *errstring);
00209 /* Retrieve the error string for the session */
00210 const char *http_get_error(http_session *sess);
00211 
00212 /**** Request hooks handling *****/
00213 
00214 typedef struct {
00215     /* A slight hack? Allows access to the hook private information,
00216      * externally... */
00217     const char *id; /* id could be a URI to be globally unique */
00218     /* e.g. "http://webdav.org/neon/hooks/davlock" */
00219     
00220     /* Register a new request: return value passed to subsequent
00221      * handlers as '_private'. Session cookie passed as 'session'. */
00222     void *(*create)(void *cookie, http_req *req, 
00223                   const char *method, const char *uri);
00224     /* Tell them what request body we are using: either buffer or stream
00225      * will be non-NULL. */
00226     void (*use_body)(void *_private, const char *buffer, FILE *stream);
00227     /* Just before sending the request: let them add headers if they want */
00228     void (*pre_send)(void *_private, sbuffer request);
00229     /* After sending the request. May return:
00230      *  HTTP_OK     everything is okay
00231      *  HTTP_RETRY  try sending the request again */
00232     int (*post_send)(void *_private, const http_status *status);
00233     /* Clean up after yourself. */
00234     void (*destroy)(void *_private);
00235 } http_request_hooks;
00236 
00237 /* Add in hooks */
00238 void http_add_hooks(http_session *sess, 
00239                   const http_request_hooks *hooks, void *cookie);
00240 
00241 /* Return private data for a new request */ 
00242 void *http_get_hook_private(http_req *req, const char *id);
00243 
00244 /***** Request Handling *****/
00245 
00246 /* Create a new request, with given method and URI. 
00247  * Returns request pointer. */
00248 http_req *
00249 http_request_create(http_session *sess, const char *method, const char *uri);
00250 
00251 /* 'buffer' will be sent as the request body with given request. */
00252 void http_set_request_body_buffer(http_req *req, const char *buffer);
00253 /* Contents of stream will be sent as the request body with the given
00254  * request */
00255 void http_set_request_body_stream(http_req *req, FILE *stream);
00256 
00257 /* Handling response bodies... you provide TWO callbacks:
00258  *
00259  * 1) 'acceptance' callback: determines whether you want to handle the
00260  * response body given the response-status information, e.g., if you
00261  * only want 2xx responses, say so here.
00262  *
00263  * 2) 'reader' callback: passed blocks of the response-body as they
00264  * arrive, if the acceptance callback returned non-zero.  */
00265 
00266 /* 'acceptance' callback type. Return non-zero to accept the response,
00267  * else zero to ignore it. */
00268 typedef int (*http_accept_response)(
00269     void *userdata, http_req *req, http_status *st);
00270 
00271 /* An 'acceptance' callback which only accepts 2xx-class responses.
00272  * Ignores userdata. */
00273 int http_accept_2xx(void *userdata, http_req *req, http_status *st);
00274 
00275 /* The 'reader' callback type */
00276 typedef void (*http_block_reader)(
00277     void *userdata, const char *buf, size_t len);
00278 
00279 /* Add a response reader for the given request, with the given
00280  * acceptance function. userdata is passed as the first argument to
00281  * the acceptance + reader callbacks. */
00282 void http_add_response_body_reader(http_req *req, http_accept_response accpt,
00283                                http_block_reader rdr, void *userdata);
00284 
00285 /* Handle response headers. Each handler is associated with a specific
00286  * header field (indicated by name). The handler is then passed the
00287  * value of this header field. */
00288 
00289 /* The header handler callback type */
00290 typedef void (*http_header_handler)(void *userdata, const char *value);
00291 
00292 /* Adds a response header handler for the given request. userdata is passed
00293  * as the first argument to the header handler, and the 'value' is the
00294  * header field value (i.e. doesn't include the "Header-Name: " part").
00295  */
00296 void http_add_response_header_handler(http_req *req, const char *name, 
00297                                   http_header_handler hdl, void *userdata);
00298 
00299 /* Add handler which is passed ALL header values regardless of name */
00300 void http_add_response_header_catcher(http_req *req, 
00301                                   http_header_handler hdl, void *userdata);
00302 
00303 /* Stock header handlers:
00304  *  'duplicate': *(char **)userdata = strdup(value)
00305  *  'numeric':   *(int *)userdata = atoi(value)
00306  * e.g.
00307  *   int mynum;
00308  *   http_add_response_header_handler(myreq, "Content-Length",
00309  *                                    http_handle_numeric_handler, &mynum);
00310  * ... arranges mynum to be set to the value of the Content-Length header.
00311  */
00312 void http_duplicate_header(void *userdata, const char *value);
00313 void http_handle_numeric_header(void *userdata, const char *value);
00314 
00315 /* Adds a header to the request with given name and value. */
00316 void http_add_request_header(http_req *req, const char *name, 
00317                           const char *value);
00318 /* Adds a header to the request with given name, using printf-like
00319  * format arguments for the value. */
00320 void http_print_request_header(http_req *req, const char *name,
00321                             const char *format, ...)
00322 #ifdef __GNUC__
00323                 __attribute__ ((format (printf, 3, 4)))
00324 #endif /* __GNUC__ */
00325 ;
00326 
00327 sbuffer http_get_request_headers(http_req *req);
00328 
00329 /* http_request_dispatch: Sends the given request, and reads the
00330  * response. Response-Status information can be retrieve with
00331  * http_get_status(req).
00332  *
00333  * Returns:
00334  *  HTTP_OK         if request sent + response read okay.
00335  *  HTTP_AUTH       if user authentication failed on origin server
00336  *  HTTP_AUTHPROXY  if user authentication failed on proxy server
00337  *  HTTP_SERVERAUTH server authentication failed
00338  *  HTTP_PROXYAUTH  proxy authentication failed
00339  *  HTTP_CONNECT    could not connect to server/proxy server
00340  *  HTTP_TIMEOUT    connection timed out mid-request
00341  *  HTTP_ERROR      for other errors, and http_get_error() should
00342  *                  return a meaningful error string
00343  *
00344  * NB: HTTP_AUTH and HTTP_AUTHPROXY mean that the USER supplied the
00345  * wrong username/password.  SERVER/PROXYAUTH mean that, after the
00346  * server has accepted a valid username/password, the server/proxy did
00347  * not authenticate the response message correctly.
00348  * */
00349 int http_request_dispatch(http_req *req);
00350 
00351 /* Returns a pointer to the response status information for the
00352  * given request. */
00353 const http_status *http_get_status(http_req *req)
00354 
00355 /* Declare this with attribute const, since we often call it >1 times
00356  * with the same argument, and it will return the same thing each
00357  * time. This lets the compiler optimize away any subsequent calls
00358  * (theoretically).  */
00359 #ifdef __GNUC__
00360                 __attribute__ ((const))
00361 #endif /* __GNUC__ */
00362     ;
00363 
00364 /* Destroy memory associated with request pointer */
00365 void http_request_destroy(http_req *req);
00366 
00367 END_NEON_DECLS
00368 
00369 #endif /* HTTP_REQUEST_H */
00370