diff --git a/ChangeLog b/ChangeLog index 92748d9..1453138 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,50 @@ Version 1.8.0 ******************************************************************************* +2011-02-07 Chandra Penke + + Add HTTPS support using OpenSSL. HTTPS support is optional and can + be enabled by passing the --enable-open-ssl argument to the + configure script. + + The following methods are introduced to the public API: + UpnpInitOpenSslContext + + When enabled, HTTPS can be used by using "https://" instead of + "http://" when passing URLs to the HTTP Client API. + +2011-02-07 Chandra Penke + + 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 Include upnpconfig.h in FileInfo.h to automatically include large diff --git a/configure.ac b/configure.ac index 9e51b09..3d43000 100644 --- a/configure.ac +++ b/configure.ac @@ -402,6 +402,11 @@ if test "x$enable_ipv6" = xyes ; then AC_DEFINE(UPNP_ENABLE_IPV6, 1, [see upnpconfig.h]) fi +RT_BOOL_ARG_ENABLE([open_ssl], [no], [open-ssl support]) +if test "x$enable_open_ssl" = xyes ; then + AC_DEFINE(UPNP_ENABLE_OPEN_SSL, 1, [see upnpconfig.h]) +fi + RT_BOOL_ARG_ENABLE([notification_reordering], [yes], [GENA notification reordering in gena_device.c]) if test "x$enable_notification_reordering" = xyes ; then AC_DEFINE(UPNP_ENABLE_NOTIFICATION_REORDERING, 1, [see upnpconfig.h]) diff --git a/upnp/inc/upnp.h b/upnp/inc/upnp.h index ec819e5..858b5ec 100644 --- a/upnp/inc/upnp.h +++ b/upnp/inc/upnp.h @@ -61,6 +61,10 @@ /* Other systems ??? */ #endif +#ifdef UPNP_ENABLE_OPEN_SSL +#include +#endif + #define LINE_SIZE 180 #define NAME_SIZE 256 #define MNFT_NAME_SIZE 64 @@ -584,6 +588,29 @@ EXPORT_SPEC int UpnpInit2( unsigned short DestPort); #endif +/*! + * \brief Initializes the OpenSSL library, and the OpenSSL context for use + * with pupnp + * + * \note This method is only enabled if pupnp is compiled with open-ssl support. + * + * \return An integer representing one of the following: + * \li \c UPNP_E_SUCCESS: The operation completed successfully. + * \li \c UPNP_E_INIT: The SDK is already initialized. + * \li \c UPNP_E_INIT_FAILED: The SDK initialization + * failed for an unknown reason. + */ +#ifdef UPNP_ENABLE_OPEN_SSL +EXPORT_SPEC int UpnpInitSslContext( + /*! If set to 1 initializes the OpenSSL library. Otherwise the application + * is responsible for initializing it. If set to 1, then OpenSSL is intialized + * with all error strings, and all ciphers loaded. */ + int initOpenSslLib, + /*! The SSL_METHOD to use to create the context. See OpenSSL docs + * for more info */ + const SSL_METHOD *sslMethod); +#endif + /*! * \brief Terminates the Linux SDK for UPnP Devices. * @@ -1885,6 +1912,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. * @@ -1926,10 +1966,12 @@ EXPORT_SPEC int UpnpDownloadUrlItem( * The SDK allocates the memory for \b handle and \b contentType, the * 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: * \li \c UPNP_E_SUCCESS: The operation completed successfully. * \li \c UPNP_E_INVALID_PARAM: Either \b url, \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. @@ -1970,10 +2012,12 @@ EXPORT_SPEC int UpnpOpenHttpGet( * The SDK allocates the memory for \b handle and \b contentType, the * 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: * \li \c UPNP_E_SUCCESS: The operation completed successfully. * \li \c UPNP_E_INVALID_PARAM: Either \b url, \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. @@ -2135,7 +2179,7 @@ EXPORT_SPEC int UpnpCloseHttpGet( * and sends the POST request to the server if the connection to the server * 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. * * \return An integer representing one of the following: @@ -2161,7 +2205,7 @@ EXPORT_SPEC int UpnpOpenHttpPost( /*! [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] 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, /*! [in] The length of the content, in bytes, being posted. */ int contentLength, @@ -2220,6 +2264,234 @@ EXPORT_SPEC int UpnpCloseHttpPost( * value is negative, timeout is infinite. */ 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. * diff --git a/upnp/inc/upnpconfig.h.in b/upnp/inc/upnpconfig.h.in index 67d2e7c..490f22a 100644 --- a/upnp/inc/upnpconfig.h.in +++ b/upnp/inc/upnpconfig.h.in @@ -107,5 +107,9 @@ * (i.e. configure --enable-ipv6) */ #undef UPNP_ENABLE_IPV6 +/** Defined to 1 if the library has been compiled with OpenSSL support + * (i.e. configure --enable-open_ssl) */ +#undef UPNP_ENABLE_OPEN_SSL + #endif /* UPNP_CONFIG_H */ diff --git a/upnp/src/api/upnpapi.c b/upnp/src/api/upnpapi.c index 9cfe182..5092672 100644 --- a/upnp/src/api/upnpapi.c +++ b/upnp/src/api/upnpapi.c @@ -78,6 +78,10 @@ #include #endif +#ifdef UPNP_ENABLE_OPEN_SSL +#include +#endif + #ifndef IN6_IS_ADDR_GLOBAL #define IN6_IS_ADDR_GLOBAL(a) \ ((((__const uint32_t *) (a))[0] & htonl(0x70000000)) \ @@ -178,6 +182,12 @@ int UpnpSdkDeviceregisteredV6 = 0; /*! Global variable used in discovery notifications. */ Upnp_SID gUpnpSdkNLSuuid; +/*! Global variable used as to store the OpenSSL context object + * to be used for all SSL/TLS connections + */ +#ifdef UPNP_ENABLE_OPEN_SSL +SSL_CTX *gSslCtx = NULL; +#endif /*! * \brief (Windows Only) Initializes the Windows Winsock library. @@ -521,6 +531,24 @@ exit_function: } #endif +#ifdef UPNP_ENABLE_OPEN_SSL +int UpnpInitSslContext(int initOpenSslLib, const SSL_METHOD *sslMethod) +{ + if (gSslCtx) + return UPNP_E_INIT; + if (initOpenSslLib) { + SSL_load_error_strings(); + SSL_library_init(); + OpenSSL_add_all_algorithms(); + } + gSslCtx = SSL_CTX_new(sslMethod); + if (!gSslCtx) { + return UPNP_E_INIT_FAILED; + } + return UPNP_E_SUCCESS; +} +#endif + #ifdef DEBUG /*! * \brief Prints thread pool statistics. @@ -590,7 +618,12 @@ int UpnpFinish(void) UpnpClient_Handle client_handle; #endif struct Handle_Info *temp; - +#ifdef UPNP_ENABLE_OPEN_SSL + if (gSslCtx) { + SSL_CTX_free(gSslCtx); + gSslCtx = NULL; + } +#endif if (UpnpSdkInit != 1) return UPNP_E_FINISH; UpnpPrintf(UPNP_INFO, API, __FILE__, __LINE__, @@ -2847,8 +2880,12 @@ int UpnpOpenHttpPost( int contentLength, int timeout) { - return http_OpenHttpPost( - url, handle, contentType, contentLength, timeout); + int status = http_OpenHttpConnection(url, handle, timeout); + if (status == UPNP_E_SUCCESS) { + return http_MakeHttpRequest(HTTPMETHOD_POST, url, handle, NULL, contentType, + contentLength, timeout); + } + return status; } @@ -2858,7 +2895,7 @@ int UpnpWriteHttpPost( size_t *size, int timeout) { - return http_WriteHttpPost(handle, buf, size, timeout); + return http_WriteHttpRequest(handle, buf, size, timeout); } @@ -2867,35 +2904,56 @@ int UpnpCloseHttpPost( int *httpStatus, 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( - const char *url_str, - void **Handle, + const char *url, + void **handle, char **contentType, int *contentLength, int *httpStatus, int timeout) { - return http_OpenHttpGet( - url_str, Handle, contentType, contentLength, httpStatus, timeout); + int status = UpnpOpenHttpConnection(url, handle, 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( - const char *url_str, + const char *url, const char *proxy_str, - void **Handle, + void **handle, char **contentType, int *contentLength, int *httpStatus, int timeout) { - return http_OpenHttpGetProxy( - url_str, proxy_str, Handle, contentType, contentLength, - httpStatus, timeout); + int status = UpnpOpenHttpConnection(proxy_str, handle, 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; } @@ -2923,13 +2981,13 @@ int UpnpCancelHttpGet(void *Handle) int UpnpCloseHttpGet(void *Handle) { - return http_CloseHttpGet(Handle); + return UpnpCloseHttpConnection(Handle); } 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); } @@ -2939,6 +2997,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 ret_code; diff --git a/upnp/src/genlib/net/http/httpparser.c b/upnp/src/genlib/net/http/httpparser.c index ccfaa59..1f84dd6 100644 --- a/upnp/src/genlib/net/http/httpparser.c +++ b/upnp/src/genlib/net/http/httpparser.c @@ -54,8 +54,9 @@ /* entity positions */ -#define NUM_HTTP_METHODS 9 +#define NUM_HTTP_METHODS 11 static str_int_entry Http_Method_Table[NUM_HTTP_METHODS] = { + {"DELETE", HTTPMETHOD_DELETE}, {"GET", HTTPMETHOD_GET}, {"HEAD", HTTPMETHOD_HEAD}, {"M-POST", HTTPMETHOD_MPOST}, @@ -65,6 +66,7 @@ static str_int_entry Http_Method_Table[NUM_HTTP_METHODS] = { {"SUBSCRIBE", HTTPMETHOD_SUBSCRIBE}, {"UNSUBSCRIBE", HTTPMETHOD_UNSUBSCRIBE}, {"POST", SOAPMETHOD_POST}, + {"PUT", HTTPMETHOD_PUT} }; #define NUM_HTTP_HEADER_NAMES 33 @@ -1454,7 +1456,8 @@ parse_status_t parser_parse_headers(INOUT http_parser_t *parser) if (tok_type == TT_CRLF) { /* end of headers */ 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 */ /*is handled separately */ return PARSE_SUCCESS; diff --git a/upnp/src/genlib/net/http/httpreadwrite.c b/upnp/src/genlib/net/http/httpreadwrite.c index fdbaa6e..2a857b6 100644 --- a/upnp/src/genlib/net/http/httpreadwrite.c +++ b/upnp/src/genlib/net/http/httpreadwrite.c @@ -162,14 +162,73 @@ static int private_connect( #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) { const char *temp_path = "/"; *fixed_url = *url; - if (token_string_casecmp(&fixed_url->scheme, "http") != 0) { +#ifdef UPNP_ENABLE_OPEN_SSL + if (token_string_casecmp(&fixed_url->scheme, "http") != 0 && + token_string_casecmp(&fixed_url->scheme, "https") != 0) + { return UPNP_E_INVALID_URL; } +#else + if (token_string_casecmp(&fixed_url->scheme, "http") != 0) + { + return UPNP_E_INVALID_URL; + } +#endif if( fixed_url->hostport.text.size == 0 ) { return UPNP_E_INVALID_URL; } @@ -720,15 +779,12 @@ int http_Download( IN const char *url_str, return ret_code; } -typedef struct HTTPPOSTHANDLE { - SOCKINFO sock_info; - int contentLength; -} http_post_handle_t; /************************************************************************ - * Function: MakePostMessage + * Function: MakeGenericMessage * * Parameters: + * http_method_t method; The type of HTTP method. * const char *url_str; String as a URL * membuffer *request; Buffer containing the request * uri_type *url; URI object containing the scheme, @@ -744,337 +800,67 @@ typedef struct HTTPPOSTHANDLE { * UPNP_E_INVALID_PARAM * UPNP_E_SUCCESS ************************************************************************/ -int MakePostMessage(const char *url_str, membuffer *request, - uri_type *url, int contentLength, const char *contentType) +int MakeGenericMessage(http_method_t method, + const char *url_str, membuffer *request, + uri_type *url, int contentLength, const char *contentType, + const UpnpString *headers) { int ret_code = 0; - char *urlPath = alloca(strlen(url_str) + 1); size_t hostlen = 0; char *hoststr; - char *temp; UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, - "DOWNLOAD URL : %s\n", url_str); - ret_code = http_FixStrUrl((char *)url_str, strlen(url_str), url); + "URL: %s method: %d\n", url_str, method); + ret_code = http_FixStrUrl(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 (contentLength >= 0) - ret_code = http_MakeMessage(request, 1, 1, - "Q" "s" "bcDCU" "T" "Nc", - HTTPMETHOD_POST, - url->pathquery.buff, - url->pathquery.size, "HOST: ", - hoststr, hostlen, contentType, - (off_t) contentLength); - else if (contentLength == UPNP_USING_CHUNKED) - ret_code = http_MakeMessage(request, 1, 1, - "Q" "s" "bcDCU" "TKc", - HTTPMETHOD_POST, - url->pathquery.buff, - url->pathquery.size, "HOST: ", - hoststr, hostlen, contentType); - else if (contentLength == UPNP_UNTIL_CLOSE) - ret_code = http_MakeMessage(request, 1, 1, - "Q" "s" "bcDCU" "Tc", - HTTPMETHOD_POST, - url->pathquery.buff, - url->pathquery.size, "HOST: ", - hoststr, hostlen, contentType); - else - ret_code = UPNP_E_INVALID_PARAM; - 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; -} - -/************************************************************************ - * 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, "%" PRIzx "\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; + ret_code = http_MakeMessage(request, 1, 1, "Q", + method, + url->pathquery.buff, + url->pathquery.size); + /* add request headers if specified, otherwise use default headers */ + if (ret_code == 0) { + if (headers) { + ret_code = http_MakeMessage(request, 1, 1, + "s", + UpnpString_get_String(headers)); + } + else { + ret_code = get_hoststr(url_str, &hoststr, &hostlen); + if (ret_code != UPNP_E_SUCCESS) + return ret_code; + UpnpPrintf(UPNP_INFO, HTTP, __FILE__, __LINE__, + "HOSTNAME : %s Length : %" PRIzu "\n", hoststr, hostlen); + ret_code = http_MakeMessage(request, 1, 1, + "s" "bcDCU", + "HOST: ", hoststr, hostlen); } - } 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; + + /* add the content-type header */ + if (ret_code == 0 && contentType) { + ret_code = http_MakeMessage(request, 1, 1, + "T", + contentType); } -} - -/************************************************************************ - * 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 == INVALID_SOCKET) { - ret_code = UPNP_E_SOCKET_ERROR; - goto errorHandler; + /* add content-length header. */ + if (ret_code == 0) { + if (contentLength >= 0) + ret_code = http_MakeMessage(request, 1, 1, "Nc", + (off_t) contentLength); + else if (contentLength == UPNP_USING_CHUNKED) + ret_code = http_MakeMessage(request, 1, 1, "Kc"); + else if (contentLength == UPNP_UNTIL_CLOSE) + ret_code = http_MakeMessage(request, 1, 1, "c"); + else + ret_code = UPNP_E_INVALID_PARAM; } - 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; - int entity_offset; - int cancel; -} http_get_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__, @@ -1084,6 +870,15 @@ int MakeGetMessage(const char *url_str, const char *proxy_str, return UPNP_E_SUCCESS; } +typedef struct HTTPCONNECTIONHANDLE { + SOCKINFO sock_info; + int contentLength; + http_parser_t response; + int requestStarted; + int cancel; +} http_connection_handle_t; + + /*! * \brief Parses already exiting data. If not complete reads more * data on the connected socket. The read data is then parsed. The @@ -1191,33 +986,272 @@ static int ReadResponseLineAndHeaders( return PARSE_OK; } + /************************************************************************ - * Function: http_ReadHttpGet + * Function: http_HttpGetProgress * * 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 + * OUT size_t *length; Buffer to get the read and parsed data + * OUT size_t *total; Size of tge buffer passed * * Description: - * Parses already existing data, then gets new data. - * Parses and extracts information from the new data. + * Extracts information from the Handle to the HTTP get object. * * Return: int - * UPNP_E_SUCCESS - On success + * UPNP_E_SUCCESS - On Sucess * 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 OUT char *buf, - IN OUT size_t *size, - IN int timeout) + 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_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 == INVALID_SOCKET) { + 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; + } +#ifdef UPNP_ENABLE_OPEN_SSL + /* For HTTPS connections start the TLS/SSL handshake. */ + if (token_string_casecmp(&url.scheme, "https") == 0) { + ret_code = sock_ssl_connect(&handle->sock_info); + if (ret_code != UPNP_E_SUCCESS) { + sock_destroy(&handle->sock_info, SD_BOTH); + goto errorHandler; + } + } +#endif +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; int num_read; int ok_on_close = FALSE; @@ -1238,8 +1272,8 @@ int http_ReadHttpGet( /* read until close */ ok_on_close = TRUE; else if ((status != PARSE_SUCCESS) - && (status != PARSE_CONTINUE_1) - && (status != PARSE_INCOMPLETE)) { + && (status != PARSE_CONTINUE_1) + && (status != PARSE_INCOMPLETE)) { /*error */ *size = 0; return UPNP_E_BAD_RESPONSE; @@ -1250,15 +1284,15 @@ int http_ReadHttpGet( !handle->cancel && handle->response.position != POS_COMPLETE) { num_read = sock_read(&handle->sock_info, tempbuf, - sizeof(tempbuf), &timeout); + sizeof(tempbuf), &timeout); if (num_read > 0) { /* append data to buffer */ ret_code = membuffer_append(&handle->response.msg.msg, - tempbuf, (size_t)num_read); + tempbuf, (size_t)num_read); if (ret_code != 0) { /* set failure status */ handle->response.http_error_code = - HTTP_INTERNAL_SERVER_ERROR; + HTTP_INTERNAL_SERVER_ERROR; *size = 0; return PARSE_FAILURE; } @@ -1301,9 +1335,9 @@ int http_ReadHttpGet( /* copy data to user buffer. delete copied data */ if (*size > 0) { memcpy(buf, &handle->response.msg.msg.buf[handle->response.entity_start_position], - *size); + *size); membuffer_delete(&handle->response.msg.msg, - handle->response.entity_start_position, *size); + handle->response.entity_start_position, *size); /* update scanner position. needed for chunked transfers */ handle->response.scanner.cursor -= *size; /* update amount discarded */ @@ -1313,204 +1347,18 @@ int http_ReadHttpGet( return UPNP_E_SUCCESS; } -/************************************************************************ - * 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) +int http_CloseHttpConnection(void *Handle) { - http_get_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; - + http_connection_handle_t *handle = Handle; if (!handle) return UPNP_E_INVALID_PARAM; /*should shutdown completely */ sock_destroy(&handle->sock_info, SD_BOTH); httpmsg_destroy(&handle->response.msg); free(handle); - 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 == INVALID_SOCKET) { - 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 * @@ -1931,7 +1779,7 @@ int http_OpenHttpGetEx( SOCKET tcp_connection; size_t sockaddr_len; membuffer request; - http_get_handle_t *handle = NULL; + http_connection_handle_t *handle = NULL; uri_type url; parse_status_t status; int errCode = UPNP_E_SUCCESS; @@ -1960,7 +1808,7 @@ int http_OpenHttpGetEx( errCode = MakeGetMessageEx(url_str, &request, &url, &rangeBuf); if (errCode != UPNP_E_SUCCESS) 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) { errCode = UPNP_E_OUTOF_MEMORY; break; diff --git a/upnp/src/genlib/net/sock.c b/upnp/src/genlib/net/sock.c index 1ec0a73..2064417 100644 --- a/upnp/src/genlib/net/sock.c +++ b/upnp/src/genlib/net/sock.c @@ -52,10 +52,19 @@ #include #include +#ifdef UPNP_ENABLE_OPEN_SSL +#include +#endif + #ifndef MSG_NOSIGNAL #define MSG_NOSIGNAL 0 #endif +#ifdef UPNP_ENABLE_OPEN_SSL +/* OpenSSL context defined in upnpapi.c */ +extern SSL_CTX *gSslCtx; +#endif + int sock_init(SOCKINFO *info, SOCKET sockfd) { assert(info); @@ -82,11 +91,37 @@ int sock_init_with_ip(SOCKINFO *info, SOCKET sockfd, return UPNP_E_SUCCESS; } +#ifdef UPNP_ENABLE_OPEN_SSL +int sock_ssl_connect(SOCKINFO *info) +{ + int status = 0; + info->ssl = SSL_new(gSslCtx); + if (!info->ssl) { + return UPNP_E_SOCKET_ERROR; + } + status = SSL_set_fd(info->ssl, info->socket); + if (status == 1) { + status = SSL_connect(info->ssl); + } + if (status == 1) { + return UPNP_E_SUCCESS; + } + return UPNP_E_SOCKET_ERROR; +} +#endif + int sock_destroy(SOCKINFO *info, int ShutdownMethod) { int ret = UPNP_E_SUCCESS; if (info->socket != INVALID_SOCKET) { +#ifdef UPNP_ENABLE_OPEN_SSL + if (info->ssl) { + SSL_shutdown(info->ssl); + SSL_free(info->ssl); + info->ssl = NULL; + } +#endif shutdown(info->socket, ShutdownMethod); if (sock_close(info->socket) == -1) { ret = UPNP_E_SOCKET_ERROR; @@ -163,16 +198,36 @@ static int sock_read_write( setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &set, sizeof(set)); #endif if (bRead) { +#ifdef UPNP_ENABLE_OPEN_SSL + if (info->ssl) { + numBytes = (long)SSL_read(info->ssl, + buffer, (size_t)bufsize); + } + else { +#endif /* read data. */ numBytes = (long)recv(sockfd, buffer, (size_t)bufsize, MSG_NOSIGNAL); +#ifdef UPNP_ENABLE_OPEN_SSL + } +#endif } else { byte_left = bufsize; bytes_sent = 0; while (byte_left > 0) { +#ifdef UPNP_ENABLE_OPEN_SSL + if (info->ssl) { + num_written = SSL_write(info->ssl, + buffer + bytes_sent, (size_t)byte_left); + } + else { +#endif /* write data. */ num_written = send(sockfd, buffer + bytes_sent, (size_t)byte_left, MSG_DONTROUTE | MSG_NOSIGNAL); +#ifdef UPNP_ENABLE_OPEN_SSL + } +#endif if (num_written == -1) { #ifdef SO_NOSIGPIPE setsockopt(sockfd, SOL_SOCKET, diff --git a/upnp/src/genlib/net/uri/uri.c b/upnp/src/genlib/net/uri/uri.c index 1491351..8e67577 100644 --- a/upnp/src/genlib/net/uri/uri.c +++ b/upnp/src/genlib/net/uri/uri.c @@ -312,6 +312,7 @@ int token_cmp(token *in1, token *in2) int parse_hostport( const char *in, size_t max, + int defaultPort, hostport_type *out) { char workbuf[256]; @@ -402,9 +403,10 @@ int parse_hostport( if (port == 0) /* Bad port number. */ return UPNP_E_INVALID_URL; - } else + } else { /* Port was not specified, use default port. */ - port = 80; + port = defaultPort; + } /* The length of the host and port string can be calculated by */ /* subtracting pointers. */ hostport_size = (size_t)(c - workbuf); @@ -673,6 +675,7 @@ int parse_uri(const char *in, size_t max, uri_type *out) int begin_path = 0; size_t begin_hostport = 0; size_t begin_fragment = 0; + int defaultPort = 80; begin_hostport = parse_scheme(in, max, &out->scheme); if (begin_hostport) { @@ -687,9 +690,13 @@ int parse_uri(const char *in, size_t max, uri_type *out) in[begin_hostport] == '/' && in[begin_hostport + 1] == '/') { begin_hostport += 2; + if (token_string_casecmp(&out->scheme, "https") == 0) { + defaultPort = 443; + } begin_path = parse_hostport(&in[begin_hostport], - max - begin_hostport, - &out->hostport); + max - begin_hostport, + defaultPort, + &out->hostport); if (begin_path >= 0) { begin_path += (int)begin_hostport; } else diff --git a/upnp/src/inc/httpparser.h b/upnp/src/inc/httpparser.h index 8f80afa..d5a1f52 100644 --- a/upnp/src/inc/httpparser.h +++ b/upnp/src/inc/httpparser.h @@ -85,16 +85,20 @@ typedef enum /* 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 { - HTTPMETHOD_POST, + HTTPMETHOD_PUT = 0, + HTTPMETHOD_DELETE = 1, + HTTPMETHOD_GET = 2, + HTTPMETHOD_HEAD = 3, + HTTPMETHOD_POST = 4, HTTPMETHOD_MPOST, HTTPMETHOD_SUBSCRIBE, HTTPMETHOD_UNSUBSCRIBE, HTTPMETHOD_NOTIFY, - HTTPMETHOD_GET, - HTTPMETHOD_HEAD, HTTPMETHOD_MSEARCH, HTTPMETHOD_UNKNOWN, SOAPMETHOD_POST, diff --git a/upnp/src/inc/httpreadwrite.h b/upnp/src/inc/httpreadwrite.h index f48ead8..c49e8a0 100644 --- a/upnp/src/inc/httpreadwrite.h +++ b/upnp/src/inc/httpreadwrite.h @@ -222,111 +222,6 @@ int http_Download( 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 * @@ -347,79 +242,242 @@ int http_HttpGetProgress( OUT size_t *length, 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, - * sends the HTTP GET request, gets the response and parses the response. + * \brief Opens a connection to the server. * - * 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 - * \li \c UPNP_E_SUCCESS - On Success - * \li \c UPNP_E_INVALID_PARAM - Invalid Paramters - * \li \c UPNP_E_OUTOF_MEMORY - * \li \c UPNP_E_SOCKET_ERROR - * \li \c UPNP_E_BAD_RESPONSE + * \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. */ -int http_OpenHttpGet( - /* [in] String as a URL. */ - const char *url_str, - /* [in,out] Pointer to buffer to store HTTP post handle. */ - void **Handle, - /* [in,out] Type of content. */ - char **contentType, - /* [out] length of content. */ - int *contentLength, - /* [out] HTTP status returned on receiving a response message. */ - int *httpStatus, - /* [in] time out value. */ +EXPORT_SPEC int http_OpenHttpConnection( + /*! [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 the HTTP GET message, connects to the peer, - * sends the HTTP GET request, gets the response and parses the response. + * \brief Makes a HTTP request using a connection previously created by + * \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 - * \li \c UPNP_E_SUCCESS - On Success - * \li \c UPNP_E_INVALID_PARAM - Invalid Paramters - * \li \c UPNP_E_OUTOF_MEMORY - * \li \c UPNP_E_SOCKET_ERROR - * \li \c UPNP_E_BAD_RESPONSE + * \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. */ -int http_OpenHttpGetProxy( - /* [in] String as a URL. */ - const char *url_str, - /* [in] String as a URL. */ - const char *proxy_str, - /* [in,out] Pointer to buffer to store HTTP post handle. */ - void **Handle, - /* [in,out] Type of content. */ - char **contentType, - /* [out] length of content. */ - int *contentLength, - /* [out] HTTP status returned on receiving a response message. */ - int *httpStatus, - /* [in] time out value. */ +EXPORT_SPEC int http_MakeHttpRequest( + /* ![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 + * host and scheme used to create the connection. */ + 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 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 * diff --git a/upnp/src/inc/sock.h b/upnp/src/inc/sock.h index 038563e..c8fed42 100644 --- a/upnp/src/inc/sock.h +++ b/upnp/src/inc/sock.h @@ -40,8 +40,12 @@ * \file */ +#include "upnpconfig.h" #include "UpnpInet.h" /* for SOCKET, netinet/in */ #include "UpnpGlobal.h" /* for UPNP_INLINE */ +#ifdef UPNP_ENABLE_OPEN_SSL +#include +#endif /* The following are not defined under winsock.h */ #ifndef SD_RECEIVE @@ -57,6 +61,9 @@ typedef struct SOCKET socket; /*! The following two fields are filled only in incoming requests. */ struct sockaddr_storage foreign_sockaddr; +#ifdef UPNP_ENABLE_OPEN_SSL + SSL *ssl; +#endif } SOCKINFO; #ifdef __cplusplus @@ -112,6 +119,20 @@ int sock_init_with_ip( /*! [in] Remote socket address. */ struct sockaddr *foreign_sockaddr); +/*! + * \brief Associates an SSL object with the socket and begins + * the client-side SSL/TLS handshake. + * + * \return Integer: + * \li \c UPNP_E_SUCCESS + * \li \c UPNP_E_SOCKET_ERROR + */ +#ifdef UPNP_ENABLE_OPEN_SSL +int sock_ssl_connect( + /*! [out] Socket Information Object. */ + SOCKINFO* info); +#endif + /*! * \brief Shutsdown the socket using the ShutdownMethod to indicate whether * sends and receives on the socket will be dis-allowed. diff --git a/upnp/src/inc/uri.h b/upnp/src/inc/uri.h index a870ca4..14a3b4e 100644 --- a/upnp/src/inc/uri.h +++ b/upnp/src/inc/uri.h @@ -288,6 +288,8 @@ int parse_hostport( const char *in, /*! [in] Sets a maximum limit. */ size_t max, + /*! [in] The default port if the port is not specified. */ + int defaultPort, /*! [out] Output parameter where the host and port are represented as * an internet address. */ hostport_type *out);