Refactor HTTP Client API

This commit is contained in:
Chandra Penke 2011-02-07 17:20:18 +05:30 committed by Marcelo Roberto Jimenez
parent ee9f83c3d5
commit 8eec345e49
7 changed files with 967 additions and 721 deletions

View File

@ -2,6 +2,38 @@
Version 1.8.0 Version 1.8.0
******************************************************************************* *******************************************************************************
2011-02-07 Chandra Penke <chandrapenke(at)mcntech.com>
Refactor HTTP Client API to be more generic.
The following features are added:
- Support for persistent HTTP connections (reusing HTTP
connections). Tthis is still a work in progress and relies on
applications to interpret the 'Connection' header
appropriately.
- Support for specifying request headers when making
requests. Useful for interacting with web services that require
custom headers.
- Support for retrieving response headers (this is a API only
change, some more work needs to be done to implement the actual
functionality. Specifically copy_msg_headers in httpreadwrite.c
needs to be implemented)
- Common API for all HTTP methods.
- Support for PUT, and DELETE methods.
The following methods are introduced to the public HTTP Client API
UpnpOpenHttpConnection, UpnpCloseHttpConnection, UpnpMakeHttpRequest,
UpnpWriteHttpRequest, UpnpEndHttpRequest, UpnpGetHttpResponse,
UpnpReadHttpResponse.
Removed a lot of duplicate code in httpreadwrite.c
2011-01-17 Chandra Penke <chandrapenke(at)mcntech.com> 2011-01-17 Chandra Penke <chandrapenke(at)mcntech.com>
Include upnpconfig.h in FileInfo.h to automatically include large Include upnpconfig.h in FileInfo.h to automatically include large

View File

@ -1766,6 +1766,19 @@ EXPORT_SPEC int UpnpUnSubscribeAsync(
* @{ * @{
*/ */
/*!
* \brief Different HTTP methods.
*/
enum Upnp_HttpMethod_e {
UPNP_HTTPMETHOD_PUT = 0,
UPNP_HTTPMETHOD_DELETE = 1,
UPNP_HTTPMETHOD_GET = 2,
UPNP_HTTPMETHOD_HEAD = 3,
UPNP_HTTPMETHOD_POST = 4
};
typedef enum Upnp_HttpMethod_e Upnp_HttpMethod;
/*! /*!
* \brief Downloads a file specified in a URL. * \brief Downloads a file specified in a URL.
* *
@ -1807,10 +1820,12 @@ EXPORT_SPEC int UpnpDownloadUrlItem(
* The SDK allocates the memory for \b handle and \b contentType, the * The SDK allocates the memory for \b handle and \b contentType, the
* application is responsible for freeing this memory. * application is responsible for freeing this memory.
* *
* \note Memory for \b contentType is freed when freeing the memory
* for handle.
*
* \return An integer representing one of the following: * \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully. * \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b url, \b handle, * \li \c UPNP_E_INVALID_PARAM: Either \b url, \b handle,
* \b contentType, \b contentLength or \b httpStatus
* is not a valid pointer. * is not a valid pointer.
* \li \c UPNP_E_INVALID_URL: The \b url is not a valid * \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* URL. * URL.
@ -1851,10 +1866,12 @@ EXPORT_SPEC int UpnpOpenHttpGet(
* The SDK allocates the memory for \b handle and \b contentType, the * The SDK allocates the memory for \b handle and \b contentType, the
* application is responsible for freeing this memory. * application is responsible for freeing this memory.
* *
* \note Memory for \b contentType is freed when freeing the memory
* for handle.
*
* \return An integer representing one of the following: * \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully. * \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b url, \b handle, * \li \c UPNP_E_INVALID_PARAM: Either \b url, \b handle,
* \b contentType, \b contentLength or \b httpStatus
* is not a valid pointer. * is not a valid pointer.
* \li \c UPNP_E_INVALID_URL: The \b url is not a valid * \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* URL. * URL.
@ -2016,7 +2033,7 @@ EXPORT_SPEC int UpnpCloseHttpGet(
* and sends the POST request to the server if the connection to the server * and sends the POST request to the server if the connection to the server
* succeeds. * succeeds.
* *
* The SDK allocates the memory for \b handle and \b contentType, the * The SDK allocates the memory for \b handle, the
* application is responsible for freeing this memory. * application is responsible for freeing this memory.
* *
* \return An integer representing one of the following: * \return An integer representing one of the following:
@ -2042,7 +2059,7 @@ EXPORT_SPEC int UpnpOpenHttpPost(
/*! [in,out] A pointer in which to store the handle for this connection. This /*! [in,out] A pointer in which to store the handle for this connection. This
* handle is required for futher operations over this connection. */ * handle is required for futher operations over this connection. */
void **handle, void **handle,
/*! [in] A buffer to store the media type of content being sent. */ /*! [in] A buffer to store the media type of content being sent. Can be NULL. */
const char *contentType, const char *contentType,
/*! [in] The length of the content, in bytes, being posted. */ /*! [in] The length of the content, in bytes, being posted. */
int contentLength, int contentLength,
@ -2101,6 +2118,234 @@ EXPORT_SPEC int UpnpCloseHttpPost(
* value is negative, timeout is infinite. */ * value is negative, timeout is infinite. */
int timeout); int timeout);
/*!
* \brief Opens a connection to the server.
*
* The SDK allocates the memory for \b handle, the
* application is responsible for freeing this memory.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b url, or \b handle
* is not a valid pointer.
* \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* URL.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_SOCKET_ERROR: Error occured allocating a socket and
* resources or an error occurred binding a socket.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int UpnpOpenHttpConnection(
/*! [in] The URL which contains the host, and the scheme to make the connection. */
const char *url,
/*! [in,out] A pointer in which to store the handle for this connection. This
* handle is required for futher operations over this connection. */
void **handle,
/*! [in] The time out value sent with the request during which a response
* is expected from the receiver, failing which, an error is reported.
* If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Makes a HTTP request using a connection previously created by
* \b UpnpOpenHttpConnection.
*
* \note Trying to make another request while a request is already being processed
* results in undefined behavior. It's up to the user to end a previous
* request by calling \b UpnpEndHttpRequest.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b url, \b handle
* or \b contentType is not a valid pointer.
* \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* URL.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_SOCKET_ERROR: Error occured allocating a socket and
* resources or an error occurred binding a socket.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int UpnpMakeHttpRequest(
/* ![in] The method to use to make the request. */
Upnp_HttpMethod method,
/*! [in] The URL to use to make the request. The URL should use the same
* scheme used to create the connection, but the host can be different
* if the request is being proxied. */
const char *url,
/*! [in] The handle to the connection. */
void *handle,
/*! [in] Headers to be used for the request. Each header should be terminated by a CRLF as specified
* in the HTTP specification. If NULL then the default headers will be used. */
UpnpString *headers,
/*! [in] The media type of content being sent. Can be NULL. */
const char *contentType,
/*! [in] The length of the content being sent, in bytes. Set to \b UPNP_USING_CHUNKED to use
* chunked encoding, or \b UPNP_UNTIL_CLOSE to avoid specifying the content length to the server.
* In this case the request is considered unfinished until the connection is closed. */
int contentLength,
/*! [in] The time out value sent with the request during which a response
* is expected from the receiver, failing which, an error is reported.
* If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Writes the content of a HTTP request initiated by a \b UpnpMakeHttpRequest call.
* The end of the content should be indicated by a call to \b UpnpEndHttpRequest
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b handle, \b buf
* or \b size is not a valid pointer.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int UpnpWriteHttpRequest(
/*! [in] The handle of the connection created by the call to
* \b UpnpOpenHttpConnection. */
void *handle,
/*! [in] The buffer containing date to be written. */
char *buf,
/*! [in] The size, in bytes of \b buf. */
size_t *size,
/*! [in] A timeout value sent with the request during which a response is
* expected from the server, failing which, an error is reported. If
* value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Indicates the end of a HTTP request previously made by
* \b UpnpMakeHttpRequest.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: \b handle is not a valid pointer.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_SOCKET_ERROR: Error occured allocating a socket and
* resources or an error occurred binding a socket.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int UpnpEndHttpRequest(
/*! [in] The handle to the connection. */
void *handle,
/*! [in] The time out value sent with the request during which a response
* is expected from the receiver, failing which, an error is reported.
* If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Gets the response from the server using a connection previously created
* by \b UpnpOpenHttpConnection
*
* \note Memory for \b contentType is only valid until the next call to the HTTP API
* for the same connection.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b handle,
* is not a valid pointer.
* \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* URL.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_NETWORK_ERROR: A network error occurred.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_READ: An error or timeout occurred reading
* from a socket.
* \li \c UPNP_E_SOCKET_BIND: An error occurred binding a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
* \li \c UPNP_E_BAD_RESPONSE: A bad response was received from the
* remote server.
*/
EXPORT_SPEC int UpnpGetHttpResponse(
/*! [in] The handle of the connection created by the call to
* \b UpnpOpenHttpConnection. */
void *handle,
/*! [in] Headers sent by the server for the response. If NULL then the
* headers are not copied. */
UpnpString *headers,
/*! [out] A buffer to store the media type of the item. */
char **contentType,
/*! [out] A pointer to store the length of the item. */
int *contentLength,
/*! [out] The status returned on receiving a response message. */
int *httpStatus,
/*! [in] The time out value sent with the request during which a response
* is expected from the server, failing which, an error is reported
* back to the user. If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Reads the content of a response using a connection previously created
* by \b UpnpOpenHttpConnection.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b handle, \b buf
* or \b size is not a valid pointer.
* \li \c UPNP_E_BAD_RESPONSE: A bad response was received from the
* remote server.
* \li \c UPNP_E_BAD_HTTPMSG: Either the request or response was in
* the incorrect format.
* \li \c UPNP_E_CANCELED: another thread called UpnpCancelHttpGet.
*
* Note: In case of return values, the status code parameter of the passed
* in handle value may provide additional information on the return
* value.
*/
EXPORT_SPEC int UpnpReadHttpResponse(
/*! [in] The handle of the connection created by the call to
* \b UpnpOpenHttpConnection. */
void *handle,
/*! [in,out] The buffer to store the read item. */
char *buf,
/*! [in,out] The size of the buffer to be read. */
size_t *size,
/*! [in] The time out value sent with the request during which a response is
* expected from the server, failing which, an error is reported back to
* the user. If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Closes the connection created with \b UpnpOpenHttpConnection
* and frees any memory associated with the connection.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: \b handle, or is not a valid pointer.
* \li \c UPNP_E_SOCKET_READ: An error or timeout occurred reading
* from a socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int UpnpCloseHttpConnection(
/*! [in] The handle of the connection to close, created by the call to
* \b UpnpOpenHttpPost. */
void *handle);
/*! /*!
* \brief Downloads an XML document specified in a URL. * \brief Downloads an XML document specified in a URL.
* *

View File

@ -2728,8 +2728,12 @@ int UpnpOpenHttpPost(
int contentLength, int contentLength,
int timeout) int timeout)
{ {
return http_OpenHttpPost( int status = http_OpenHttpConnection(url, handle, timeout);
url, handle, contentType, contentLength, timeout); if (status == UPNP_E_SUCCESS) {
return http_MakeHttpRequest(HTTPMETHOD_POST, url, handle, NULL, contentType,
contentLength, timeout);
}
return status;
} }
@ -2739,7 +2743,7 @@ int UpnpWriteHttpPost(
size_t *size, size_t *size,
int timeout) int timeout)
{ {
return http_WriteHttpPost(handle, buf, size, timeout); return http_WriteHttpRequest(handle, buf, size, timeout);
} }
@ -2748,35 +2752,56 @@ int UpnpCloseHttpPost(
int *httpStatus, int *httpStatus,
int timeout) int timeout)
{ {
return http_CloseHttpPost(handle, httpStatus, timeout); int status = http_EndHttpRequest(handle, timeout);
} if (status == UPNP_E_SUCCESS) {
status = http_GetHttpResponse(handle, NULL, NULL, NULL, httpStatus, timeout);
}
status = http_CloseHttpConnection(handle);
return status;}
int UpnpOpenHttpGet( int UpnpOpenHttpGet(
const char *url_str, const char *url,
void **Handle, void **handle,
char **contentType, char **contentType,
int *contentLength, int *contentLength,
int *httpStatus, int *httpStatus,
int timeout) int timeout)
{ {
return http_OpenHttpGet( int status = UpnpOpenHttpConnection(url, handle, timeout);
url_str, Handle, contentType, contentLength, httpStatus, timeout); if (status == UPNP_E_SUCCESS) {
status = UpnpMakeHttpRequest(HTTPMETHOD_GET, url, *handle, NULL, NULL, 0, timeout);
}
if (status == UPNP_E_SUCCESS) {
status = UpnpEndHttpRequest(*handle, timeout);
}
if (status == UPNP_E_SUCCESS) {
status = UpnpGetHttpResponse(*handle, NULL, contentType, contentLength, httpStatus, timeout);
}
return status;
} }
int UpnpOpenHttpGetProxy( int UpnpOpenHttpGetProxy(
const char *url_str, const char *url,
const char *proxy_str, const char *proxy_str,
void **Handle, void **handle,
char **contentType, char **contentType,
int *contentLength, int *contentLength,
int *httpStatus, int *httpStatus,
int timeout) int timeout)
{ {
return http_OpenHttpGetProxy( int status = UpnpOpenHttpConnection(proxy_str, handle, timeout);
url_str, proxy_str, Handle, contentType, contentLength, if (status == UPNP_E_SUCCESS) {
httpStatus, timeout); status = UpnpMakeHttpRequest(HTTPMETHOD_GET, url, *handle, NULL, NULL, 0, timeout);
}
if (status == UPNP_E_SUCCESS) {
status = UpnpEndHttpRequest(*handle, timeout);
}
if (status == UPNP_E_SUCCESS) {
status = UpnpGetHttpResponse(*handle, NULL, contentType, contentLength, httpStatus, timeout);
}
return status;
} }
@ -2804,13 +2829,13 @@ int UpnpCancelHttpGet(void *Handle)
int UpnpCloseHttpGet(void *Handle) int UpnpCloseHttpGet(void *Handle)
{ {
return http_CloseHttpGet(Handle); return UpnpCloseHttpConnection(Handle);
} }
int UpnpReadHttpGet(void *Handle, char *buf, size_t *size, int timeout) int UpnpReadHttpGet(void *Handle, char *buf, size_t *size, int timeout)
{ {
return http_ReadHttpGet(Handle, buf, size, timeout); return http_ReadHttpResponse(Handle, buf, size, timeout);
} }
@ -2820,6 +2845,57 @@ int UpnpHttpGetProgress(void *Handle, size_t *length, size_t *total)
} }
int UpnpOpenHttpConnection(const char *url,
void **handle, int timeout)
{
return http_OpenHttpConnection(url, handle, timeout);
}
int UpnpMakeHttpRequest(Upnp_HttpMethod method, const char *url,
void *handle, UpnpString *headers,
const char *contentType, int contentLength,
int timeout)
{
return http_MakeHttpRequest(method, url, handle, headers, contentType,
contentLength, timeout);
}
int UpnpWriteHttpRequest(void *handle, char *buf,
size_t *size, int timeout)
{
return http_WriteHttpRequest(handle, buf, size, timeout);
}
int UpnpEndHttpRequest(void *handle, int timeout)
{
return http_EndHttpRequest(handle, timeout);
}
int UpnpGetHttpResponse(void *handle, UpnpString *headers,
char **contentType, int *contentLength, int *httpStatus,
int timeout)
{
return http_GetHttpResponse(handle, headers, contentType, contentLength,
httpStatus, timeout);
}
int UpnpReadHttpResponse(void *handle, char *buf,
size_t *size, int timeout)
{
return http_ReadHttpResponse(handle, buf, size, timeout);
}
int UpnpCloseHttpConnection(void *handle)
{
return http_CloseHttpConnection(handle);
}
int UpnpDownloadUrlItem(const char *url, char **outBuf, char *contentType) int UpnpDownloadUrlItem(const char *url, char **outBuf, char *contentType)
{ {
int ret_code; int ret_code;

View File

@ -54,8 +54,9 @@
/* entity positions */ /* entity positions */
#define NUM_HTTP_METHODS 9 #define NUM_HTTP_METHODS 11
static str_int_entry Http_Method_Table[NUM_HTTP_METHODS] = { static str_int_entry Http_Method_Table[NUM_HTTP_METHODS] = {
{"DELETE", HTTPMETHOD_DELETE},
{"GET", HTTPMETHOD_GET}, {"GET", HTTPMETHOD_GET},
{"HEAD", HTTPMETHOD_HEAD}, {"HEAD", HTTPMETHOD_HEAD},
{"M-POST", HTTPMETHOD_MPOST}, {"M-POST", HTTPMETHOD_MPOST},
@ -65,6 +66,7 @@ static str_int_entry Http_Method_Table[NUM_HTTP_METHODS] = {
{"SUBSCRIBE", HTTPMETHOD_SUBSCRIBE}, {"SUBSCRIBE", HTTPMETHOD_SUBSCRIBE},
{"UNSUBSCRIBE", HTTPMETHOD_UNSUBSCRIBE}, {"UNSUBSCRIBE", HTTPMETHOD_UNSUBSCRIBE},
{"POST", SOAPMETHOD_POST}, {"POST", SOAPMETHOD_POST},
{"PUT", HTTPMETHOD_PUT}
}; };
#define NUM_HTTP_HEADER_NAMES 33 #define NUM_HTTP_HEADER_NAMES 33
@ -1450,7 +1452,8 @@ parse_status_t parser_parse_headers(INOUT http_parser_t *parser)
if (tok_type == TT_CRLF) { if (tok_type == TT_CRLF) {
/* end of headers */ /* end of headers */
if ((parser->msg.is_request) if ((parser->msg.is_request)
&& (parser->msg.method == HTTPMETHOD_POST)) { && (parser->msg.method == HTTPMETHOD_POST ||
parser->msg.method == HTTPMETHOD_PUT)) {
parser->position = POS_COMPLETE; /*post entity parsing */ parser->position = POS_COMPLETE; /*post entity parsing */
/*is handled separately */ /*is handled separately */
return PARSE_SUCCESS; return PARSE_SUCCESS;

View File

@ -39,7 +39,6 @@
#include "config.h" #include "config.h"
#include "httpreadwrite.h" #include "httpreadwrite.h"
#include "unixutil.h" #include "unixutil.h"
#include "upnp.h" #include "upnp.h"
#include "upnpapi.h" #include "upnpapi.h"
@ -162,6 +161,56 @@ static int private_connect(
#endif /* UPNP_ENABLE_BLOCKING_TCP_CONNECTIONS */ #endif /* UPNP_ENABLE_BLOCKING_TCP_CONNECTIONS */
} }
static int get_hoststr(const char* url_str,
char **hoststr,
size_t *hostlen)
{
char *urlPath = alloca(strlen(url_str) + 1);
char *temp;
strcpy(urlPath, url_str);
*hoststr = strstr(urlPath, "//");
if (*hoststr == NULL)
return UPNP_E_INVALID_URL;
*hoststr += 2;
temp = strchr(*hoststr, '/');
if (temp == NULL)
return UPNP_E_INVALID_URL;
*temp = '\0';
*hostlen = strlen(*hoststr);
*temp = '/';
return UPNP_E_SUCCESS;
}
static void copy_msg_headers(IN LinkedList *msgHeaders,
OUT UpnpString *headers)
{
return;
/* TODO: */
#if 0
ListNode *node;
UpnpHttpHeader *header;
http_header_t *msgHeader;
if (headers) {
ListInit(headers, NULL, (free_function) UpnpHttpHeader_delete);
node = ListHead(msgHeaders);
while(node) {
msgHeader = (http_header_t*) node->item;
header = UpnpHttpHeader_new();
UpnpHttpHeader_strncpy_Name(
header,
msgHeader->name.buf,
msgHeader->name.length);
UpnpHttpHeader_strncpy_Value(
header,
msgHeader->value.buf,
msgHeader->value.length);
node = ListNext(msgHeaders, node);
}
}
#endif
}
int http_FixUrl(IN uri_type *url, OUT uri_type *fixed_url) int http_FixUrl(IN uri_type *url, OUT uri_type *fixed_url)
{ {
const char *temp_path = "/"; const char *temp_path = "/";
@ -717,15 +766,12 @@ int http_Download( IN const char *url_str,
return ret_code; return ret_code;
} }
typedef struct HTTPPOSTHANDLE {
SOCKINFO sock_info;
int contentLength;
} http_post_handle_t;
/************************************************************************ /************************************************************************
* Function: MakePostMessage * Function: MakeGenericMessage
* *
* Parameters: * Parameters:
* http_method_t method; The type of HTTP method.
* const char *url_str; String as a URL * const char *url_str; String as a URL
* membuffer *request; Buffer containing the request * membuffer *request; Buffer containing the request
* uri_type *url; URI object containing the scheme, * uri_type *url; URI object containing the scheme,
@ -741,59 +787,63 @@ typedef struct HTTPPOSTHANDLE {
* UPNP_E_INVALID_PARAM * UPNP_E_INVALID_PARAM
* UPNP_E_SUCCESS * UPNP_E_SUCCESS
************************************************************************/ ************************************************************************/
int MakePostMessage(const char *url_str, membuffer *request, int MakeGenericMessage(http_method_t method,
uri_type *url, int contentLength, const char *contentType) const char *url_str, membuffer *request,
uri_type *url, int contentLength, const char *contentType,
const UpnpString *headers)
{ {
int ret_code = 0; int ret_code = 0;
char *urlPath = alloca(strlen(url_str) + 1);
size_t hostlen = 0; size_t hostlen = 0;
char *hoststr; char *hoststr;
char *temp;
UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
"DOWNLOAD URL : %s\n", url_str); "URL: %s method: %d\n", url_str, method);
ret_code = http_FixStrUrl((char *)url_str, strlen(url_str), url); ret_code = http_FixStrUrl(url_str, strlen(url_str), url);
if (ret_code != UPNP_E_SUCCESS) if (ret_code != UPNP_E_SUCCESS)
return ret_code; return ret_code;
/* make msg */ /* make msg */
membuffer_init(request); membuffer_init(request);
strcpy(urlPath, url_str); ret_code = http_MakeMessage(request, 1, 1, "Q",
hoststr = strstr(urlPath, "//"); method,
if (hoststr == NULL) url->pathquery.buff,
return UPNP_E_INVALID_URL; url->pathquery.size);
hoststr += 2; /* add request headers if specified, otherwise use default headers */
temp = strchr(hoststr, '/'); if (ret_code == 0) {
if (temp == NULL) if (headers) {
return UPNP_E_INVALID_URL; ret_code = http_MakeMessage(request, 1, 1,
*temp = '\0'; "s",
hostlen = strlen(hoststr); UpnpString_get_String(headers));
*temp = '/'; }
else {
ret_code = get_hoststr(url_str, &hoststr, &hostlen);
if (ret_code != UPNP_E_SUCCESS)
return ret_code;
UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
"HOSTNAME : %s Length : %" PRIzu "\n", hoststr, hostlen); "HOSTNAME : %s Length : %" PRIzu "\n", hoststr, hostlen);
if (contentLength >= 0)
ret_code = http_MakeMessage(request, 1, 1, ret_code = http_MakeMessage(request, 1, 1,
"Q" "s" "bcDCU" "T" "Nc", "s" "bcDCU",
HTTPMETHOD_POST, "HOST: ", hoststr, hostlen);
url->pathquery.buff, }
url->pathquery.size, "HOST: ", }
hoststr, hostlen, contentType,
/* add the content-type header */
if (ret_code == 0 && contentType) {
ret_code = http_MakeMessage(request, 1, 1,
"T",
contentType);
}
/* add content-length header. */
if (ret_code == 0) {
if (contentLength >= 0)
ret_code = http_MakeMessage(request, 1, 1, "Nc",
(off_t) contentLength); (off_t) contentLength);
else if (contentLength == UPNP_USING_CHUNKED) else if (contentLength == UPNP_USING_CHUNKED)
ret_code = http_MakeMessage(request, 1, 1, ret_code = http_MakeMessage(request, 1, 1, "Kc");
"Q" "s" "bcDCU" "TKc",
HTTPMETHOD_POST,
url->pathquery.buff,
url->pathquery.size, "HOST: ",
hoststr, hostlen, contentType);
else if (contentLength == UPNP_UNTIL_CLOSE) else if (contentLength == UPNP_UNTIL_CLOSE)
ret_code = http_MakeMessage(request, 1, 1, ret_code = http_MakeMessage(request, 1, 1, "c");
"Q" "s" "bcDCU" "Tc",
HTTPMETHOD_POST,
url->pathquery.buff,
url->pathquery.size, "HOST: ",
hoststr, hostlen, contentType);
else else
ret_code = UPNP_E_INVALID_PARAM; ret_code = UPNP_E_INVALID_PARAM;
}
if (ret_code != 0) { if (ret_code != 0) {
UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
"HTTP Makemessage failed\n"); "HTTP Makemessage failed\n");
@ -807,279 +857,14 @@ int MakePostMessage(const char *url_str, membuffer *request,
return UPNP_E_SUCCESS; return UPNP_E_SUCCESS;
} }
/************************************************************************ typedef struct HTTPCONNECTIONHANDLE {
* Function: http_WriteHttpPost
*
* Parameters:
* IN void *Handle: Handle to the http post object
* IN char *buf: Buffer to send to peer, if format used
* is not UPNP_USING_CHUNKED,
* IN unsigned int *size: Size of the data to be sent.
* IN int timeout: time out value
*
* Description:
* Formats data if format used is UPNP_USING_CHUNKED.
* Writes data on the socket connected to the peer.
*
* Return: int
* UPNP_E_SUCCESS - On Success
* UPNP_E_INVALID_PARAM - Invalid Parameter
* -1 - On Socket Error.
************************************************************************/
int http_WriteHttpPost( IN void *Handle,
IN char *buf,
IN size_t *size,
IN int timeout )
{
http_post_handle_t *handle = (http_post_handle_t *)Handle;
char *tempbuf = NULL;
size_t tempbufSize = 0;
int freeTempbuf = 0;
int numWritten = 0;
if (!handle || !size || !buf) {
if (size)
*size = 0;
return UPNP_E_INVALID_PARAM;
}
if (handle->contentLength == UPNP_USING_CHUNKED) {
if (*size) {
size_t tempSize = 0;
tempbuf = malloc(*size +
CHUNK_HEADER_SIZE + CHUNK_TAIL_SIZE);
if (!tempbuf)
return UPNP_E_OUTOF_MEMORY;
/* begin chunk */
sprintf(tempbuf, "%zx\r\n", *size);
tempSize = strlen(tempbuf);
memcpy(tempbuf + tempSize, buf, *size);
memcpy(tempbuf + tempSize + *size, "\r\n", 2);
/* end of chunk */
tempbufSize = tempSize + *size + 2;
freeTempbuf = 1;
}
} else {
tempbuf = buf;
tempbufSize = *size;
}
numWritten =
sock_write(&handle->sock_info, tempbuf, tempbufSize, &timeout);
if (freeTempbuf)
free(tempbuf);
if (numWritten < 0) {
*size = 0;
return numWritten;
} else {
*size = (size_t)numWritten;
return UPNP_E_SUCCESS;
}
}
/************************************************************************
* Function: http_CloseHttpPost
*
* Parameters:
* IN void *Handle; Handle to the http post object
* IN OUT int *httpStatus; HTTP status returned on receiving a
* response message
* IN int timeout; time out value
*
* Description:
* Sends remaining data if using UPNP_USING_CHUNKED
* format. Receives any more messages. Destroys socket and any socket
* associated memory. Frees handle associated with the HTTP POST msg.
*
* Return: int
* UPNP_E_SUCCESS - On success
* UPNP_E_INVALID_PARAM - Invalid Parameter
************************************************************************/
int http_CloseHttpPost(IN void *Handle, IN OUT int *httpStatus, IN int timeout)
{
int retc = 0;
http_parser_t response;
int http_error_code;
const char *zcrlf = "0\r\n\r\n";
http_post_handle_t *handle = Handle;
if ((!handle) || (!httpStatus))
return UPNP_E_INVALID_PARAM;
if (handle->contentLength == UPNP_USING_CHUNKED)
/*send last chunk */
retc = sock_write(&handle->sock_info, zcrlf, strlen(zcrlf), &timeout);
/*read response */
parser_response_init(&response, HTTPMETHOD_POST);
retc = http_RecvMessage(&handle->sock_info, &response,
HTTPMETHOD_POST, &timeout, &http_error_code);
*httpStatus = http_error_code;
/*should shutdown completely */
sock_destroy(&handle->sock_info, SD_BOTH);
httpmsg_destroy(&response.msg);
free(handle);
return retc;
}
/************************************************************************
* Function: http_OpenHttpPost
*
* Parameters:
* IN const char *url_str; String as a URL
* IN OUT void **Handle; Pointer to buffer to store HTTP
* post handle
* IN const char *contentType; Type of content
* IN int contentLength; length of content
* IN int timeout; time out value
*
* Description:
* Makes the HTTP POST message, connects to the peer,
* sends the HTTP POST request. Adds the post handle to buffer of
* such handles
*
* Return : int;
* UPNP_E_SUCCESS - On success
* UPNP_E_INVALID_PARAM - Invalid Parameter
* UPNP_E_OUTOF_MEMORY
* UPNP_E_SOCKET_ERROR
* UPNP_E_SOCKET_CONNECT
************************************************************************/
int http_OpenHttpPost(
IN const char *url_str,
IN OUT void **Handle,
IN const char *contentType,
IN int contentLength,
IN int timeout)
{
int ret_code;
size_t sockaddr_len;
SOCKET tcp_connection;
membuffer request;
http_post_handle_t *handle = NULL;
uri_type url;
if (!url_str || !Handle || !contentType)
return UPNP_E_INVALID_PARAM;
*Handle = handle;
ret_code = MakePostMessage(url_str, &request, &url,
contentLength, contentType);
if (ret_code != UPNP_E_SUCCESS)
return ret_code;
handle = malloc(sizeof(http_post_handle_t));
if (!handle)
return UPNP_E_OUTOF_MEMORY;
handle->contentLength = contentLength;
tcp_connection = socket(url.hostport.IPaddress.ss_family,
SOCK_STREAM, 0);
if (tcp_connection == -1) {
ret_code = UPNP_E_SOCKET_ERROR;
goto errorHandler;
}
if (sock_init(&handle->sock_info, tcp_connection) != UPNP_E_SUCCESS) {
sock_destroy(&handle->sock_info, SD_BOTH);
ret_code = UPNP_E_SOCKET_ERROR;
goto errorHandler;
}
sockaddr_len = url.hostport.IPaddress.ss_family == AF_INET6 ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
ret_code = private_connect(handle->sock_info.socket,
(struct sockaddr *)&(url.hostport.IPaddress),
(socklen_t)sockaddr_len);
if (ret_code == -1) {
sock_destroy(&handle->sock_info, SD_BOTH);
ret_code = UPNP_E_SOCKET_CONNECT;
goto errorHandler;
}
/* send request */
ret_code = http_SendMessage(&handle->sock_info, &timeout, "b",
request.buf, request.length);
if (ret_code != 0)
sock_destroy(&handle->sock_info, SD_BOTH);
errorHandler:
membuffer_destroy(&request);
*Handle = handle;
return ret_code;
}
typedef struct HTTPGETHANDLE {
http_parser_t response;
SOCKINFO sock_info; SOCKINFO sock_info;
int entity_offset; int contentLength;
http_parser_t response;
int requestStarted;
int cancel; int cancel;
} http_get_handle_t; } http_connection_handle_t;
/************************************************************************
* Function: MakeGetMessage
*
* Parameters:
* const char *url_str ; String as a URL
* const char *proxy_str ; String as a URL of proxy to use
* membuffer *request ; Buffer containing the request
* uri_type *url ; URI object containing the scheme, path
* query token, etc.
*
* Description:
* Makes the message for the HTTP GET method
*
* Returns:
* UPNP_E_INVALID_URL
* Error Codes returned by http_MakeMessage
* UPNP_E_SUCCESS
************************************************************************/
int MakeGetMessage(const char *url_str, const char *proxy_str,
membuffer *request, uri_type *url)
{
int ret_code;
char *urlPath = alloca(strlen(url_str) + 1);
size_t querylen = 0;
const char *querystr;
size_t hostlen = 0;
char *hoststr, *temp;
UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
"DOWNLOAD URL : %s\n", url_str);
ret_code = http_FixStrUrl((char *)url_str, strlen(url_str), url);
if (ret_code != UPNP_E_SUCCESS)
return ret_code;
/* make msg */
membuffer_init(request);
strcpy(urlPath, url_str);
hoststr = strstr(urlPath, "//");
if (hoststr == NULL)
return UPNP_E_INVALID_URL;
hoststr += 2;
temp = strchr(hoststr, '/');
if (temp == NULL)
return UPNP_E_INVALID_URL;
*temp = '\0';
hostlen = strlen(hoststr);
*temp = '/';
UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
"HOSTNAME : %s Length : %" PRIzu "\n", hoststr, hostlen);
if (proxy_str) {
querystr = url_str;
querylen = strlen(querystr);
} else {
querystr = url->pathquery.buff;
querylen = url->pathquery.size;
}
ret_code = http_MakeMessage(request, 1, 1,
"Q" "s" "bcDCUc",
HTTPMETHOD_GET, querystr, querylen,
"HOST: ", hoststr, hostlen);
if (ret_code != 0) {
UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
"HTTP Makemessage failed\n");
membuffer_destroy(request);
return ret_code;
}
UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__,
"HTTP Buffer:\n%s\n" "----------END--------\n",
request->buf);
return UPNP_E_SUCCESS;
}
/*! /*!
* \brief Parses already exiting data. If not complete reads more * \brief Parses already exiting data. If not complete reads more
@ -1188,33 +973,262 @@ static int ReadResponseLineAndHeaders(
return PARSE_OK; return PARSE_OK;
} }
/************************************************************************ /************************************************************************
* Function: http_ReadHttpGet * Function: http_HttpGetProgress
* *
* Parameters: * Parameters:
* IN void *Handle; Handle to the HTTP get object * IN void *Handle; Handle to the HTTP get object
* IN OUT char *buf; Buffer to get the read and parsed data * OUT size_t *length; Buffer to get the read and parsed data
* IN OUT size_t *size; Size of the buffer passed * OUT size_t *total; Size of tge buffer passed
* IN int timeout; time out value
* *
* Description: * Description:
* Parses already existing data, then gets new data. * Extracts information from the Handle to the HTTP get object.
* Parses and extracts information from the new data.
* *
* Return: int * Return: int
* UPNP_E_SUCCESS - On success * UPNP_E_SUCCESS - On Sucess
* UPNP_E_INVALID_PARAM - Invalid Parameter * UPNP_E_INVALID_PARAM - Invalid Parameter
* UPNP_E_BAD_RESPONSE
* UPNP_E_BAD_HTTPMSG
* UPNP_E_CANCELED
************************************************************************/ ************************************************************************/
int http_ReadHttpGet( int http_HttpGetProgress(
IN void *Handle, IN void *Handle,
IN OUT char *buf, OUT size_t *length,
IN OUT size_t *size, OUT size_t *total)
IN int timeout)
{ {
http_get_handle_t *handle = Handle; http_connection_handle_t *handle = Handle;
if (!handle || !length || !total) {
return UPNP_E_INVALID_PARAM;
}
*length = handle->response.msg.entity.length;
*total = handle->response.content_length;
return UPNP_E_SUCCESS;
}
/************************************************************************
* Function: http_CancelHttpGet
*
* Parameters:
* IN void *Handle; Handle to HTTP get object
*
* Description:
* Set the cancel flag of the HttpGet handle
*
* Return: int
* UPNP_E_SUCCESS - On Success
* UPNP_E_INVALID_PARAM - Invalid Parameter
************************************************************************/
int http_CancelHttpGet(IN void *Handle)
{
http_connection_handle_t *handle = Handle;
if (!handle)
return UPNP_E_INVALID_PARAM;
handle->cancel = 1;
return UPNP_E_SUCCESS;
}
int http_OpenHttpConnection(const char *url_str, void **Handle, int timeout)
{
int ret_code;
size_t sockaddr_len;
SOCKET tcp_connection;
http_connection_handle_t *handle = NULL;
uri_type url;
if (!url_str || !Handle)
return UPNP_E_INVALID_PARAM;
*Handle = handle;
/* parse url_str */
ret_code = http_FixStrUrl(url_str, strlen(url_str), &url);
if (ret_code != UPNP_E_SUCCESS)
return ret_code;
/* create the handle */
handle = malloc(sizeof(http_connection_handle_t));
if (!handle) {
return UPNP_E_OUTOF_MEMORY;
}
handle->requestStarted = 0;
memset(&handle->response, 0, sizeof(handle->response));
/* connect to the server */
tcp_connection = socket(url.hostport.IPaddress.ss_family, SOCK_STREAM, 0);
if (tcp_connection == -1) {
ret_code = UPNP_E_SOCKET_ERROR;
goto errorHandler;
}
if (sock_init(&handle->sock_info, tcp_connection) != UPNP_E_SUCCESS) {
sock_destroy(&handle->sock_info, SD_BOTH);
ret_code = UPNP_E_SOCKET_ERROR;
goto errorHandler;
}
sockaddr_len = url.hostport.IPaddress.ss_family == AF_INET6 ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
ret_code = private_connect(handle->sock_info.socket,
(struct sockaddr *)&(url.hostport.IPaddress),
(socklen_t) sockaddr_len);
if (ret_code == -1) {
sock_destroy(&handle->sock_info, SD_BOTH);
ret_code = UPNP_E_SOCKET_CONNECT;
goto errorHandler;
}
errorHandler:
*Handle = handle;
return ret_code;
}
int http_MakeHttpRequest(Upnp_HttpMethod method,
const char *url_str, void *Handle, UpnpString *headers,
const char *contentType, int contentLength,
int timeout)
{
int ret_code;
membuffer request;
http_connection_handle_t *handle = Handle;
uri_type url;
if (!url_str || !Handle)
return UPNP_E_INVALID_PARAM;
if (handle->requestStarted) {
/* TODO: Log an error that a previous request is already in progress. */
}
handle->requestStarted = 1;
handle->cancel = 0;
ret_code = MakeGenericMessage(method, url_str, &request, &url, contentLength,
contentType, headers);
if (ret_code != UPNP_E_SUCCESS)
return ret_code;
/* send request */
ret_code = http_SendMessage(&handle->sock_info, &timeout, "b",
request.buf, request.length);
membuffer_destroy(&request);
httpmsg_destroy(&handle->response.msg);
parser_response_init(&handle->response, method);
return ret_code;
}
int http_WriteHttpRequest(void *Handle, char *buf,
size_t *size, int timeout)
{
http_connection_handle_t *handle = (http_connection_handle_t *)Handle;
char *tempbuf = NULL;
size_t tempbufSize = 0;
int freeTempbuf = 0;
int numWritten = 0;
if (!handle || !size || !buf) {
if (size)
*size = 0;
return UPNP_E_INVALID_PARAM;
}
if (handle->contentLength == UPNP_USING_CHUNKED) {
if (*size) {
size_t tempSize = 0;
tempbuf = malloc(*size +
CHUNK_HEADER_SIZE + CHUNK_TAIL_SIZE);
if (!tempbuf)
return UPNP_E_OUTOF_MEMORY;
/* begin chunk */
sprintf(tempbuf, "%zx\r\n", *size);
tempSize = strlen(tempbuf);
memcpy(tempbuf + tempSize, buf, *size);
memcpy(tempbuf + tempSize + *size, "\r\n", 2);
/* end of chunk */
tempbufSize = tempSize + *size + 2;
freeTempbuf = 1;
}
} else {
tempbuf = buf;
tempbufSize = *size;
}
numWritten =
sock_write(&handle->sock_info, tempbuf, tempbufSize, &timeout);
if (freeTempbuf)
free(tempbuf);
if (numWritten < 0) {
*size = 0;
return numWritten;
} else {
*size = (size_t)numWritten;
return UPNP_E_SUCCESS;
}
}
int http_EndHttpRequest(void *Handle, int timeout)
{
int retc = 0;
const char *zcrlf = "0\r\n\r\n";
http_connection_handle_t *handle = Handle;
if (!handle)
return UPNP_E_INVALID_PARAM;
if (!handle->requestStarted) {
return UPNP_E_SUCCESS;
}
handle->requestStarted = 0;
if (handle->contentLength == UPNP_USING_CHUNKED)
/*send last chunk */
retc = sock_write(&handle->sock_info, zcrlf, strlen(zcrlf), &timeout);
return retc >= 0 ? UPNP_E_SUCCESS : UPNP_E_SOCKET_WRITE;
}
int http_GetHttpResponse(void *Handle, UpnpString *headers,
char **contentType, int *contentLength,
int *httpStatus, int timeout)
{
int ret_code;
int http_error_code;
memptr ctype;
http_connection_handle_t *handle = Handle;
parse_status_t status;
status = ReadResponseLineAndHeaders(&handle->sock_info,
&handle->response, &timeout,
&http_error_code);
if (status != PARSE_OK) {
ret_code = UPNP_E_BAD_RESPONSE;
goto errorHandler;
}
status = parser_get_entity_read_method(&handle->response);
if (status != PARSE_CONTINUE_1 && status != PARSE_SUCCESS) {
ret_code = UPNP_E_BAD_RESPONSE;
goto errorHandler;
}
ret_code = UPNP_E_SUCCESS;
if (httpStatus) {
*httpStatus = handle->response.msg.status_code;
}
if (contentType) {
if (!httpmsg_find_hdr(&handle->response.msg, HDR_CONTENT_TYPE, &ctype))
/* no content-type */
*contentType = NULL;
else
*contentType = ctype.buf;
}
if (contentLength) {
if (handle->response.position == POS_COMPLETE)
*contentLength = 0;
else if (handle->response.ent_position == ENTREAD_USING_CHUNKED)
*contentLength = UPNP_USING_CHUNKED;
else if (handle->response.ent_position == ENTREAD_USING_CLEN)
*contentLength = (int)handle->response.content_length;
else if (handle->response.ent_position == ENTREAD_UNTIL_CLOSE)
*contentLength = UPNP_UNTIL_CLOSE;
}
if (headers) {
copy_msg_headers(&handle->response.msg.headers, headers);
}
errorHandler:
if (ret_code != UPNP_E_SUCCESS)
httpmsg_destroy(&handle->response.msg);
return ret_code;
}
int http_ReadHttpResponse(void *Handle, char *buf, size_t *size, int timeout)
{
http_connection_handle_t *handle = Handle;
parse_status_t status; parse_status_t status;
int num_read; int num_read;
int ok_on_close = FALSE; int ok_on_close = FALSE;
@ -1310,204 +1324,18 @@ int http_ReadHttpGet(
return UPNP_E_SUCCESS; return UPNP_E_SUCCESS;
} }
/************************************************************************ int http_CloseHttpConnection(void *Handle)
* Function: http_HttpGetProgress
*
* Parameters:
* IN void *Handle; Handle to the HTTP get object
* OUT size_t *length; Buffer to get the read and parsed data
* OUT size_t *total; Size of tge buffer passed
*
* Description:
* Extracts information from the Handle to the HTTP get object.
*
* Return: int
* UPNP_E_SUCCESS - On Sucess
* UPNP_E_INVALID_PARAM - Invalid Parameter
************************************************************************/
int http_HttpGetProgress(
IN void *Handle,
OUT size_t *length,
OUT size_t *total)
{ {
http_get_handle_t *handle = Handle; http_connection_handle_t *handle = Handle;
if (!handle || !length || !total) {
return UPNP_E_INVALID_PARAM;
}
*length = handle->response.msg.entity.length;
*total = handle->response.content_length;
return UPNP_E_SUCCESS;
}
/************************************************************************
* Function: http_CancelHttpGet
*
* Parameters:
* IN void *Handle; Handle to HTTP get object
*
* Description:
* Set the cancel flag of the HttpGet handle
*
* Return: int
* UPNP_E_SUCCESS - On Success
* UPNP_E_INVALID_PARAM - Invalid Parameter
************************************************************************/
int http_CancelHttpGet(IN void *Handle)
{
http_get_handle_t *handle = Handle;
if (!handle)
return UPNP_E_INVALID_PARAM;
handle->cancel = 1;
return UPNP_E_SUCCESS;
}
/************************************************************************
* Function: http_CloseHttpGet
*
* Parameters:
* IN void *Handle; Handle to HTTP get object
*
* Description:
* Clears the handle allocated for the HTTP GET operation
* Clears socket states and memory allocated for socket operations.
*
* Return: int
* UPNP_E_SUCCESS - On Success
* UPNP_E_INVALID_PARAM - Invalid Parameter
************************************************************************/
int http_CloseHttpGet(IN void *Handle)
{
http_get_handle_t *handle = Handle;
if (!handle) if (!handle)
return UPNP_E_INVALID_PARAM; return UPNP_E_INVALID_PARAM;
/*should shutdown completely */ /*should shutdown completely */
sock_destroy(&handle->sock_info, SD_BOTH); sock_destroy(&handle->sock_info, SD_BOTH);
httpmsg_destroy(&handle->response.msg); httpmsg_destroy(&handle->response.msg);
free(handle); free(handle);
return UPNP_E_SUCCESS; return UPNP_E_SUCCESS;
} }
int http_OpenHttpGet( IN const char *url_str,
IN OUT void **Handle,
IN OUT char **contentType,
OUT int *contentLength,
OUT int *httpStatus,
IN int timeout)
{
return http_OpenHttpGetProxy(
url_str, NULL, Handle, contentType, contentLength, httpStatus,
timeout);
}
int http_OpenHttpGetProxy(const char *url_str, const char *proxy_str,
void **Handle, char **contentType, int *contentLength,
int *httpStatus, int timeout)
{
int ret_code;
size_t sockaddr_len;
int http_error_code;
memptr ctype;
SOCKET tcp_connection;
membuffer request;
http_get_handle_t *handle = NULL;
uri_type url;
uri_type proxy;
uri_type *peer;
parse_status_t status;
if (!url_str || !Handle || !contentType || !httpStatus)
return UPNP_E_INVALID_PARAM;
*httpStatus = 0;
*Handle = handle;
*contentType = NULL;
*contentLength = 0;
ret_code = MakeGetMessage(url_str, proxy_str, &request, &url);
if (ret_code != UPNP_E_SUCCESS)
return ret_code;
if (proxy_str) {
ret_code =
http_FixStrUrl((char *)proxy_str, strlen(proxy_str),
&proxy);
peer = &proxy;
} else {
peer = &url;
}
handle = malloc(sizeof(http_get_handle_t));
if (!handle)
return UPNP_E_OUTOF_MEMORY;
handle->cancel = 0;
parser_response_init(&handle->response, HTTPMETHOD_GET);
tcp_connection =
socket(peer->hostport.IPaddress.ss_family, SOCK_STREAM, 0);
if (tcp_connection == -1) {
ret_code = UPNP_E_SOCKET_ERROR;
goto errorHandler;
}
if (sock_init(&handle->sock_info, tcp_connection) != UPNP_E_SUCCESS) {
sock_destroy(&handle->sock_info, SD_BOTH);
ret_code = UPNP_E_SOCKET_ERROR;
goto errorHandler;
}
sockaddr_len = peer->hostport.IPaddress.ss_family == AF_INET6 ?
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
ret_code = private_connect(handle->sock_info.socket,
(struct sockaddr *)&(peer->hostport.IPaddress),
(socklen_t) sockaddr_len);
if (ret_code == -1) {
sock_destroy(&handle->sock_info, SD_BOTH);
ret_code = UPNP_E_SOCKET_CONNECT;
goto errorHandler;
}
/* send request */
ret_code = http_SendMessage(&handle->sock_info, &timeout, "b",
request.buf, request.length);
if (ret_code) {
sock_destroy(&handle->sock_info, SD_BOTH);
goto errorHandler;
}
status = ReadResponseLineAndHeaders(&handle->sock_info,
&handle->response, &timeout,
&http_error_code);
if (status != PARSE_OK) {
ret_code = UPNP_E_BAD_RESPONSE;
goto errorHandler;
}
status = parser_get_entity_read_method(&handle->response);
if (status != PARSE_CONTINUE_1 && status != PARSE_SUCCESS) {
ret_code = UPNP_E_BAD_RESPONSE;
goto errorHandler;
}
*httpStatus = handle->response.msg.status_code;
ret_code = UPNP_E_SUCCESS;
if (!httpmsg_find_hdr(&handle->response.msg, HDR_CONTENT_TYPE, &ctype))
/* no content-type */
*contentType = NULL;
else
*contentType = ctype.buf;
if (handle->response.position == POS_COMPLETE)
*contentLength = 0;
else if (handle->response.ent_position == ENTREAD_USING_CHUNKED)
*contentLength = UPNP_USING_CHUNKED;
else if (handle->response.ent_position == ENTREAD_USING_CLEN)
*contentLength = (int)handle->response.content_length;
else if (handle->response.ent_position == ENTREAD_UNTIL_CLOSE)
*contentLength = UPNP_UNTIL_CLOSE;
errorHandler:
*Handle = handle;
membuffer_destroy(&request);
if (ret_code != UPNP_E_SUCCESS)
httpmsg_destroy(&handle->response.msg);
return ret_code;
}
/************************************************************************ /************************************************************************
* Function: http_SendStatusResponse * Function: http_SendStatusResponse
* *
@ -1928,7 +1756,7 @@ int http_OpenHttpGetEx(
SOCKET tcp_connection; SOCKET tcp_connection;
size_t sockaddr_len; size_t sockaddr_len;
membuffer request; membuffer request;
http_get_handle_t *handle = NULL; http_connection_handle_t *handle = NULL;
uri_type url; uri_type url;
parse_status_t status; parse_status_t status;
int errCode = UPNP_E_SUCCESS; int errCode = UPNP_E_SUCCESS;
@ -1957,7 +1785,7 @@ int http_OpenHttpGetEx(
errCode = MakeGetMessageEx(url_str, &request, &url, &rangeBuf); errCode = MakeGetMessageEx(url_str, &request, &url, &rangeBuf);
if (errCode != UPNP_E_SUCCESS) if (errCode != UPNP_E_SUCCESS)
break; break;
handle = (http_get_handle_t *)malloc(sizeof(http_get_handle_t)); handle = (http_connection_handle_t *)malloc(sizeof(http_connection_handle_t));
if (!handle) { if (!handle) {
errCode = UPNP_E_OUTOF_MEMORY; errCode = UPNP_E_OUTOF_MEMORY;
break; break;

View File

@ -85,16 +85,20 @@ typedef enum
/* end of private section. */ /* end of private section. */
/* method in a HTTP request. */ /* method in a HTTP request.
* IMPORTANT: The enum values of the standard HTTP method should match
* those of Upnp_HttpMethod enum defined in upnp.h */
typedef enum typedef enum
{ {
HTTPMETHOD_POST, HTTPMETHOD_PUT = 0,
HTTPMETHOD_DELETE = 1,
HTTPMETHOD_GET = 2,
HTTPMETHOD_HEAD = 3,
HTTPMETHOD_POST = 4,
HTTPMETHOD_MPOST, HTTPMETHOD_MPOST,
HTTPMETHOD_SUBSCRIBE, HTTPMETHOD_SUBSCRIBE,
HTTPMETHOD_UNSUBSCRIBE, HTTPMETHOD_UNSUBSCRIBE,
HTTPMETHOD_NOTIFY, HTTPMETHOD_NOTIFY,
HTTPMETHOD_GET,
HTTPMETHOD_HEAD,
HTTPMETHOD_MSEARCH, HTTPMETHOD_MSEARCH,
HTTPMETHOD_UNKNOWN, HTTPMETHOD_UNKNOWN,
SOAPMETHOD_POST, SOAPMETHOD_POST,

View File

@ -222,111 +222,6 @@ int http_Download(
OUT char* content_type ); OUT char* content_type );
/************************************************************************
* Function: http_WriteHttpPost
*
* Parameters:
* IN void *Handle: Handle to the http post object
* IN char *buf: Buffer to send to peer, if format used
* is not UPNP_USING_CHUNKED,
* IN size_t *size: Size of the data to be sent.
* IN int timeout: time out value
*
* Description:
* Formats data if format used is UPNP_USING_CHUNKED.
* Writes data on the socket connected to the peer.
*
* Return: int
* UPNP_E_SUCCESS - On Success
* UPNP_E_INVALID_PARAM - Invalid Parameter
* -1 - On Socket Error.
************************************************************************/
int http_WriteHttpPost(IN void *Handle,
IN char *buf,
IN size_t *size,
IN int timeout);
/************************************************************************
* Function: http_CloseHttpPost
*
* Parameters:
* IN void *Handle; Handle to the http post object
* IN OUT int *httpStatus; HTTP status returned on receiving a
* response message
* IN int timeout; time out value
*
* Description:
* Sends remaining data if using UPNP_USING_CHUNKED
* format. Receives any more messages. Destroys socket and any socket
* associated memory. Frees handle associated with the HTTP POST msg.
*
* Return: int
* UPNP_E_SUCCESS - On success
* UPNP_E_INVALID_PARAM - Invalid Parameter
************************************************************************/
int http_CloseHttpPost(IN void *Handle,
IN OUT int *httpStatus,
IN int timeout);
/************************************************************************
* Function: http_OpenHttpPost
*
* Parameters:
* IN const char *url_str; String as a URL
* IN OUT void **Handle; Pointer to buffer to store HTTP
* post handle
* IN const char *contentType; Type of content
* IN int contentLength; length of content
* IN int timeout; time out value
*
* Description:
* Makes the HTTP POST message, connects to the peer,
* sends the HTTP POST request. Adds the post handle to buffer of
* such handles
*
* Return : int;
* UPNP_E_SUCCESS - On success
* UPNP_E_INVALID_PARAM - Invalid Parameter
* UPNP_E_OUTOF_MEMORY
* UPNP_E_SOCKET_ERROR
* UPNP_E_SOCKET_CONNECT
************************************************************************/
int http_OpenHttpPost(IN const char *url_str,
IN OUT void **Handle,
IN const char *contentType,
IN int contentLength,
IN int timeout);
/************************************************************************
* Function: http_ReadHttpGet
*
* Parameters:
* IN void *Handle; Handle to the HTTP get object
* IN OUT char *buf; Buffer to get the read and parsed data
* IN OUT size_t *size; Size of the buffer passed
* IN int timeout; time out value
*
* Description:
* Parses already existing data, then gets new data.
* Parses and extracts information from the new data.
*
* Return: int
* UPNP_E_SUCCESS - On success
* UPNP_E_INVALID_PARAM - Invalid Parameter
* UPNP_E_BAD_RESPONSE
* UPNP_E_BAD_HTTPMSG
* UPNP_E_CANCELED
************************************************************************/
int http_ReadHttpGet(
IN void *Handle,
IN OUT char *buf,
IN OUT size_t *size,
IN int timeout);
/************************************************************************ /************************************************************************
* Function: http_HttpGetProgress * Function: http_HttpGetProgress
* *
@ -347,79 +242,242 @@ int http_HttpGetProgress(
OUT size_t *length, OUT size_t *length,
OUT size_t *total); OUT size_t *total);
/************************************************************************
* Function: http_CloseHttpGet
*
* Parameters:
* IN void *Handle; Handle to HTTP get object
*
* Description:
* Clears the handle allocated for the HTTP GET operation
* Clears socket states and memory allocated for socket operations.
*
* Return: int
* UPNP_E_SUCCESS - On Success
* UPNP_E_INVALID_PARAM - Invalid Parameter
************************************************************************/
int http_CloseHttpGet(IN void *Handle);
/*! /*!
* \brief Makes the HTTP GET message, connects to the peer, * \brief Opens a connection to the server.
* sends the HTTP GET request, gets the response and parses the response.
* *
* If a proxy URL is defined then the connection is made there. * The SDK allocates the memory for \b handle, the
* application is responsible for freeing this memory.
* *
* \return integer * \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS - On Success * \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM - Invalid Paramters * \li \c UPNP_E_INVALID_PARAM: Either \b url, or \b handle
* \li \c UPNP_E_OUTOF_MEMORY * is not a valid pointer.
* \li \c UPNP_E_SOCKET_ERROR * \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* \li \c UPNP_E_BAD_RESPONSE * URL.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_SOCKET_ERROR: Error occured allocating a socket and
* resources or an error occurred binding a socket.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/ */
int http_OpenHttpGet( EXPORT_SPEC int http_OpenHttpConnection(
/* [in] String as a URL. */ /*! [in] The URL which contains the host, and the scheme to make the connection. */
const char *url_str, const char *url,
/* [in,out] Pointer to buffer to store HTTP post handle. */ /*! [in,out] A pointer in which to store the handle for this connection. This
void **Handle, * handle is required for futher operations over this connection. */
/* [in,out] Type of content. */ void **handle,
char **contentType, /*! [in] The time out value sent with the request during which a response
/* [out] length of content. */ * is expected from the receiver, failing which, an error is reported.
int *contentLength, * If value is negative, timeout is infinite. */
/* [out] HTTP status returned on receiving a response message. */
int *httpStatus,
/* [in] time out value. */
int timeout); int timeout);
/*! /*!
* \brief Makes the HTTP GET message, connects to the peer, * \brief Makes a HTTP request using a connection previously created by
* sends the HTTP GET request, gets the response and parses the response. * \b UpnpOpenHttpConnection.
* *
* If a proxy URL is defined then the connection is made there. * \note Trying to make another request while a request is already being processed
* results in undefined behavior. It's up to the user to end a previous
* request by calling \b UpnpEndHttpRequest.
* *
* \return integer * \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS - On Success * \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM - Invalid Paramters * \li \c UPNP_E_INVALID_PARAM: Either \b url, \b handle
* \li \c UPNP_E_OUTOF_MEMORY * or \b contentType is not a valid pointer.
* \li \c UPNP_E_SOCKET_ERROR * \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* \li \c UPNP_E_BAD_RESPONSE * URL.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_SOCKET_ERROR: Error occured allocating a socket and
* resources or an error occurred binding a socket.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/ */
int http_OpenHttpGetProxy( EXPORT_SPEC int http_MakeHttpRequest(
/* [in] String as a URL. */ /* ![in] The method to use to make the request. */
const char *url_str, Upnp_HttpMethod method,
/* [in] String as a URL. */ /*! [in] The URL to use to make the request. The URL should use the same
const char *proxy_str, * host and scheme used to create the connection. */
/* [in,out] Pointer to buffer to store HTTP post handle. */ const char *url,
void **Handle, /*! [in] The handle to the connection. */
/* [in,out] Type of content. */ void *handle,
char **contentType, /*! [in] Headers to be used for the request. Each header should be terminated by a CRLF as specified
/* [out] length of content. */ * in the HTTP specification. If NULL then the default headers will be used. */
int *contentLength, UpnpString *headers,
/* [out] HTTP status returned on receiving a response message. */ /*! [in] The media type of content being sent. Can be NULL. */
int *httpStatus, const char *contentType,
/* [in] time out value. */ /*! [in] The length of the content being sent, in bytes. Set to \b UPNP_USING_CHUNKED to use
* chunked encoding, or \b UPNP_UNTIL_CLOSE to avoid specifying the content length to the server.
* In this case the request is considered unfinished until the connection is closed. */
int contentLength,
/*! [in] The time out value sent with the request during which a response
* is expected from the receiver, failing which, an error is reported.
* If value is negative, timeout is infinite. */
int timeout); int timeout);
/*!
* \brief Writes the content of a HTTP request initiated by a \b UpnpMakeHttpRequest call.
* The end of the content should be indicated by a call to \b UpnpEndHttpRequest
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b handle, \b buf
* or \b size is not a valid pointer.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int http_WriteHttpRequest(
/*! [in] The handle of the connection created by the call to
* \b UpnpOpenHttpConnection. */
void *handle,
/*! [in] The buffer containing date to be written. */
char *buf,
/*! [in] The size, in bytes of \b buf. */
size_t *size,
/*! [in] A timeout value sent with the request during which a response is
* expected from the server, failing which, an error is reported. If
* value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Indicates the end of a HTTP request previously made by
* \b UpnpMakeHttpRequest.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: \b handle is not a valid pointer.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_SOCKET_ERROR: Error occured allocating a socket and
* resources or an error occurred binding a socket.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int http_EndHttpRequest(
/*! [in] The handle to the connection. */
void *handle,
/*! [in] The time out value sent with the request during which a response
* is expected from the receiver, failing which, an error is reported.
* If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Gets the response from the server using a connection previously created
* by \b UpnpOpenHttpConnection
*
* \note Memory for \b contentType is only valid until the next call to the HTTP API
* for the same connection.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b handle,
* \b contentType, \b contentLength or \b httpStatus
* is not a valid pointer.
* \li \c UPNP_E_INVALID_URL: The \b url is not a valid
* URL.
* \li \c UPNP_E_OUTOF_MEMORY: Insufficient resources exist to
* download this file.
* \li \c UPNP_E_NETWORK_ERROR: A network error occurred.
* \li \c UPNP_E_SOCKET_WRITE: An error or timeout occurred writing
* to a socket.
* \li \c UPNP_E_SOCKET_READ: An error or timeout occurred reading
* from a socket.
* \li \c UPNP_E_SOCKET_BIND: An error occurred binding a socket.
* \li \c UPNP_E_SOCKET_CONNECT: An error occurred connecting a
* socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
* \li \c UPNP_E_BAD_RESPONSE: A bad response was received from the
* remote server.
*/
EXPORT_SPEC int http_GetHttpResponse(
/*! [in] The handle of the connection created by the call to
* \b UpnpOpenHttpConnection. */
void *handle,
/*! [in] Headers sent by the server for the response. If NULL then the
* headers are not copied. */
UpnpString *headers,
/*! [out] A buffer to store the media type of the item. */
char **contentType,
/*! [out] A pointer to store the length of the item. */
int *contentLength,
/*! [out] The status returned on receiving a response message. */
int *httpStatus,
/*! [in] The time out value sent with the request during which a response
* is expected from the server, failing which, an error is reported
* back to the user. If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Reads the content of a response using a connection previously created
* by \b UpnpOpenHttpConnection.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: Either \b handle, \b buf
* or \b size is not a valid pointer.
* \li \c UPNP_E_BAD_RESPONSE: A bad response was received from the
* remote server.
* \li \c UPNP_E_BAD_HTTPMSG: Either the request or response was in
* the incorrect format.
* \li \c UPNP_E_CANCELED: another thread called UpnpCancelHttpGet.
*
* Note: In case of return values, the status code parameter of the passed
* in handle value may provide additional information on the return
* value.
*/
EXPORT_SPEC int http_ReadHttpResponse(
/*! [in] The handle of the connection created by the call to
* \b UpnpOpenHttpConnection. */
void *handle,
/*! [in,out] The buffer to store the read item. */
char *buf,
/*! [in,out] The size of the buffer to be read. */
size_t *size,
/*! [in] The time out value sent with the request during which a response is
* expected from the server, failing which, an error is reported back to
* the user. If value is negative, timeout is infinite. */
int timeout);
/*!
* \brief Closes the connection created with \b UpnpOpenHttpConnection
* and frees any memory associated with the connection.
*
* \return An integer representing one of the following:
* \li \c UPNP_E_SUCCESS: The operation completed successfully.
* \li \c UPNP_E_INVALID_PARAM: \b handle, or is not a valid pointer.
* \li \c UPNP_E_SOCKET_READ: An error or timeout occurred reading
* from a socket.
* \li \c UPNP_E_OUTOF_SOCKET: Too many sockets are currently
* allocated.
*/
EXPORT_SPEC int http_CloseHttpConnection(
/*! [in] The handle of the connection to close, created by the call to
* \b UpnpOpenHttpPost. */
void *handle);
/************************************************************************ /************************************************************************
* Function: http_SendStatusResponse * Function: http_SendStatusResponse
* *