text: /* $Id$ */
  /* 
   * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
   */
  #ifndef __PJLIB_UTIL_HTTP_CLIENT_H__
  #define __PJLIB_UTIL_HTTP_CLIENT_H__
  
  /**
   * @file http_client.h
   * @brief Simple HTTP Client
   */
  #include <pj/activesock.h>
  #include <pjlib-util/types.h>
  
  PJ_BEGIN_DECL
  
  /**
   * @defgroup PJ_HTTP_CLIENT Simple HTTP Client
   * @ingroup PJ_PROTOCOLS
   * @{
   * This contains a simple HTTP client implementation.
   * Some known limitations: 
   * - Does not support chunked Transfer-Encoding.
   */
  
  /**
   * This opaque structure describes the http request.
   */
  typedef struct pj_http_req pj_http_req;
  
  /**
   * Defines the maximum number of elements in a pj_http_headers
   * structure.
   */
  #define PJ_HTTP_HEADER_SIZE 32
  
  /**
   * HTTP header representation.
   */
  typedef struct pj_http_header_elmt
  {
      pj_str_t name;	/**< Header name */
      pj_str_t value;	/**< Header value */
  } pj_http_header_elmt;
  
  /**
   * This structure describes http request/response headers.
   * Application should call #pj_http_headers_add_elmt() to
   * add a header field.
   */
  typedef struct pj_http_headers
  {
      /**< Number of header fields */
      unsigned     count;
  
      /** Header elements/fields */
      pj_http_header_elmt header[PJ_HTTP_HEADER_SIZE];
  } pj_http_headers;
  
  /**
   * Structure to save HTTP authentication credential.
   */
  typedef struct pj_http_auth_cred
  {
      /**
       * Specify specific authentication schemes to be responded. Valid values
       * are "basic" and "digest". If this field is not set, any authentication
       * schemes will be responded.
       *
       * Default is empty.
       */
      pj_str_t	scheme;
  
      /**
       * Specify specific authentication realm to be responded. If this field
       * is set, only 401/407 response with matching realm will be responded.
       * If this field is not set, any realms will be responded.
       *
       * Default is empty.
       */
      pj_str_t	realm;
  
      /**
       * Specify authentication username.
       *
       * Default is empty.
       */
      pj_str_t	username;
  
      /**
       * The type of password in \a data field. Currently only 0 is
       * supported, meaning the \a data contains plain-text password.
       *
       * Default is 0.
       */
      unsigned	data_type;
  
      /**
       * Specify authentication password. The encoding of the password depends
       * on the value of \a data_type field above.
       *
       * Default is empty.
       */
      pj_str_t	data;
  
  } pj_http_auth_cred;
  
  
  /**
   * Parameters that can be given during http request creation. Application
   * must initialize this structure with #pj_http_req_param_default().
   */
  typedef struct pj_http_req_param 
  {
      /** 
       * The address family of the URL.
       *  Default is pj_AF_INET().
       */
      int             addr_family;
  
      /** 
       * The HTTP request method.
       * Default is GET.
       */
      pj_str_t        method;
  
      /** 
       * The HTTP protocol version ("1.0" or "1.1").
       * Default is "1.0".
       */
      pj_str_t        version;
  
      /** 
       * HTTP request operation timeout.
       * Default is PJ_HTTP_DEFAULT_TIMEOUT.
       */
      pj_time_val     timeout;
  
      /** 
       * User-defined data.
       * Default is NULL.
       */
      void            *user_data;
  
      /** 
       * HTTP request headers.
       * Default is empty.
       */
      pj_http_headers headers;
  
      /**
        * This structure describes the http request body. If application
        * specifies the data to send, the data must remain valid until 
        * the HTTP request is sent. Alternatively, application can choose
        * to specify total_size as the total data size to send instead
        * while leaving the data NULL (and its size 0). In this case,
        * HTTP request will then call on_send_data() callback once it is 
        * ready to send the request body. This will be useful if 
        * application does not wish to load the data into the buffer at 
        * once.
        * 
        * Default is empty.
        */
      struct pj_http_reqdata
      {
          void       *data;          /**< Request body data */
          pj_size_t  size;           /**< Request body size */
          pj_size_t  total_size;     /**< If total_size > 0, data */
                                     /**< will be provided later  */
      } reqdata;
  
      /**
       * Authentication credential needed to respond to 401/407 response.
       */
      pj_http_auth_cred	auth_cred;
  
      /**
       * Optional source port range to use when binding the socket.
       * This can be used if the source port needs to be within a certain range
       * for instance due to strict firewall settings. The port used will be
       * randomized within the range.
       *
       * Note that if authentication is configured, the authentication response
       * will be a new transaction
       *
       * Default is 0 (The OS will select the source port automatically)
       */
      pj_uint16_t		source_port_range_start;
  
      /**
       * Optional source port range to use when binding.
       * The size of the port restriction range
       *
       * Default is 0 (The OS will select the source port automatically))
       */
      pj_uint16_t		source_port_range_size;
  
      /**
       * Max number of retries if binding to a port fails.
       * Note that this does not adress the scenario where a request times out
       * or errors. This needs to be taken care of by the on_complete callback.
       *
       * Default is 3
       */
      pj_uint16_t		max_retries;
  
  } pj_http_req_param;
  
  /**
   * HTTP authentication challenge, parsed from WWW-Authenticate header.
   */
  typedef struct pj_http_auth_chal
  {
      pj_str_t	scheme;		/**< Auth scheme.		*/
      pj_str_t	realm;		/**< Realm for the challenge.	*/
      pj_str_t	domain;		/**< Domain.			*/
      pj_str_t	nonce;		/**< Nonce challenge.		*/
      pj_str_t	opaque;		/**< Opaque value.		*/
      int		stale;		/**< Stale parameter.		*/
      pj_str_t	algorithm;	/**< Algorithm parameter.	*/
      pj_str_t	qop;		/**< Quality of protection.	*/
  } pj_http_auth_chal;
  
  /**
   * This structure describes HTTP response.
   */
  typedef struct pj_http_resp
  {
      pj_str_t        version;        /**< HTTP version of the server */
      pj_uint16_t     status_code;    /**< Status code of the request */
      pj_str_t        reason;         /**< Reason phrase */
      pj_http_headers headers;        /**< Response headers */
      pj_http_auth_chal auth_chal;    /**< Parsed WWW-Authenticate header, if
  				         any. */
      pj_int32_t      content_length; /**< The value of content-length header
  					 field. -1 if not specified. */
      void            *data;          /**< Data received */
      pj_size_t       size;           /**< Data size */
  } pj_http_resp;
  
  /**
   * This structure describes HTTP URL.
   */
  typedef struct pj_http_url
  {
      pj_str_t	username;	    /**< Username part */
      pj_str_t	passwd;		    /**< Password part */
      pj_str_t    protocol;           /**< Protocol used */
      pj_str_t    host;               /**< Host name */
      pj_uint16_t port;               /**< Port number */
      pj_str_t    path;               /**< Path */
  } pj_http_url;
  
  /**
   * This structure describes the callbacks to be called by the HTTP request.
   */
  typedef struct pj_http_req_callback
  {
      /**
       * This callback is called when a complete HTTP response header 
       * is received.
       *
       * @param http_req	The http request.
       * @param resp	The response of the request.
       */
      void (*on_response)(pj_http_req *http_req, const pj_http_resp *resp);
  
      /**
       * This callback is called when the HTTP request is ready to send
       * its request body. Application may wish to use this callback if
       * it wishes to load the data at a later time or if it does not 
       * wish to load the whole data into memory. In order for this
       * callback to be called, application MUST set http_req_param.total_size
       * to a value greater than 0.
       *
       * @param http_req	The http request.
       * @param data	Pointer to the data that will be sent. Application
       *                  must set the pointer to the current data chunk/segment
       *                  to be sent. Data must remain valid until the next 
       *                  on_send_data() callback or for the last segment,
       *                  until it is sent.
       * @param size	Pointer to the data size that will be sent.
       */
      void (*on_send_data)(pj_http_req *http_req,
                           void **data, pj_size_t *size);
  
      /**
       * This callback is called when a segment of response body data
       * arrives. If this callback is specified (i.e. not NULL), the
       * on_complete() callback will be called with zero-length data
       * (within the response parameter), hence the application must 
       * store and manage its own data buffer, otherwise the 
       * on_complete() callback will be called with the response 
       * parameter containing the complete data. 
       * 
       * @param http_req	The http request.
       * @param data	The buffer containing the data.
       * @param size	The length of data in the buffer.
       */
      void (*on_data_read)(pj_http_req *http_req,
                           void *data, pj_size_t size);
  
      /**
       * This callback is called when the HTTP request is completed.
       * If the callback on_data_read() is specified, the variable
       * response->data will be set to NULL, otherwise it will
       * contain the complete data. Response data is allocated from
       * pj_http_req's internal memory pool so the data remain valid
       * as long as pj_http_req is not destroyed and application does
       * not start a new request.
       *
       * If no longer required, application may choose to destroy 
       * pj_http_req immediately by calling #pj_http_req_destroy() inside 
       * the callback.
       *
       * @param http_req	The http request.
       * @param status	The status of the request operation. PJ_SUCCESS
       *                  if the operation completed successfully
       *                  (connection-wise). To check the server's 
       *                  status-code response to the HTTP request, 
       *                  application should check resp->status_code instead.
       * @param resp	The response of the corresponding request. If 
       *			the status argument is non-PJ_SUCCESS, this 
       *			argument will be set to NULL.
       */
      void (*on_complete)(pj_http_req *http_req,
                          pj_status_t status,
                          const pj_http_resp *resp);
  
  } pj_http_req_callback;
  
  
  /**
   * Initialize the http request parameters with the default values.
   *
   * @param param		The parameter to be initialized.
   */
  PJ_DECL(void) pj_http_req_param_default(pj_http_req_param *param);
  
  /**
   * Add a header element/field. Application MUST make sure that 
   * name and val pointer remains valid until the HTTP request is sent.
   *
   * @param headers	The headers.
   * @param name	        The header field name.
   * @param value	        The header field value.
   *
   * @return	        PJ_SUCCESS if the operation has been successful,
   *		        or the appropriate error code on failure.
   */
  PJ_DECL(pj_status_t) pj_http_headers_add_elmt(pj_http_headers *headers, 
                                                pj_str_t *name, 
                                                pj_str_t *val);
  
  /** 
   * The same as #pj_http_headers_add_elmt() with char * as
   * its parameters. Application MUST make sure that name and val pointer 
   * remains valid until the HTTP request is sent.
   *
   * @param headers	The headers.
   * @param name	        The header field name.
   * @param value	        The header field value.
   *
   * @return	        PJ_SUCCESS if the operation has been successful,
   *		        or the appropriate error code on failure.
   */
  PJ_DECL(pj_status_t) pj_http_headers_add_elmt2(pj_http_headers *headers, 
                                                 char *name, char *val);
  
  /**
   * Parse a http URL into its components.
   *
   * @param url	        The URL to be parsed.
   * @param hurl	        Pointer to receive the parsed result.
   *
   * @return	        PJ_SUCCESS if the operation has been successful,
   *		        or the appropriate error code on failure.
   */
  PJ_DECL(pj_status_t) pj_http_req_parse_url(const pj_str_t *url, 
                                             pj_http_url *hurl);
  
  /**
   * Create the HTTP request.
   *
   * @param pool		Pool to use. HTTP request will use the pool's factory
   *                      to allocate its own memory pool.
   * @param url		HTTP URL request.
   * @param timer	        The timer to use.
   * @param ioqueue	The ioqueue to use.
   * @param param		Optional parameters. When this parameter is not 
   *                      specifed (NULL), the default values will be used.
   * @param hcb		Pointer to structure containing application
   *			callbacks.
   * @param http_req	Pointer to receive the http request instance.
   *
   * @return		PJ_SUCCESS if the operation has been successful,
   *			or the appropriate error code on failure.
   */
  PJ_DECL(pj_status_t) pj_http_req_create(pj_pool_t *pool,
                                          const pj_str_t *url,
  					pj_timer_heap_t *timer,
  					pj_ioqueue_t *ioqueue,
                                          const pj_http_req_param *param,
                                          const pj_http_req_callback *hcb,
                                          pj_http_req **http_req);
  
  /**
   * Set the timeout of the HTTP request operation. Note that if the 
   * HTTP request is currently running, the timeout will only affect 
   * subsequent request operations.
   *
   * @param http_req  The http request.
   * @param timeout   Timeout value for HTTP request operation.
   */
  PJ_DECL(void) pj_http_req_set_timeout(pj_http_req *http_req,
                                        const pj_time_val* timeout);
  
  /**
   * Starts an asynchronous HTTP request to the URL specified.
   *
   * @param http_req  The http request.
   *
   * @return
   *  - PJ_SUCCESS    if success
   *  - non-zero      which indicates the appropriate error code.
   */
  PJ_DECL(pj_status_t) pj_http_req_start(pj_http_req *http_req);
  
  /**
   * Cancel the asynchronous HTTP request. 
   *
   * @param http_req  The http request.
   * @param notify    If non-zero, the on_complete() callback will be 
   *                  called with status PJ_ECANCELLED to notify that 
   *                  the query has been cancelled.
   *
   * @return
   *  - PJ_SUCCESS    if success
   *  - non-zero      which indicates the appropriate error code.
   */
  PJ_DECL(pj_status_t) pj_http_req_cancel(pj_http_req *http_req,
                                          pj_bool_t notify);
  
  /**
   * Destroy the http request.
   *
   * @param http_req	The http request to be destroyed.
   *
   * @return              PJ_SUCCESS if success.
   */
  PJ_DECL(pj_status_t) pj_http_req_destroy(pj_http_req *http_req);
  
  /**
   * Find out whether the http request is running.
   *
   * @param http_req      The http request.
   *
   * @return	        PJ_TRUE if a request is pending, or
   *		        PJ_FALSE if idle
   */
  PJ_DECL(pj_bool_t) pj_http_req_is_running(const pj_http_req *http_req);
  
  /**
   * Retrieve the user data previously associated with this http
   * request.
   *
   * @param http_req  The http request.
   *
   * @return	    The user data.
   */
  PJ_DECL(void *) pj_http_req_get_user_data(pj_http_req *http_req);
  
  /**
   * @}
   */
  
  PJ_END_DECL
  
  
  #endif	/* __PJLIB_UTIL_HTTP_CLIENT_H__ */
  