From: pradeep kumar B Date: Thu, 28 Apr 2016 09:45:22 +0000 (+0530) Subject: [capi-http] Implemented the http authentication & http credential apis X-Git-Tag: submit/tizen/20160614.043312~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F06%2F67806%2F8;p=platform%2Fcore%2Fapi%2Fhttp.git [capi-http] Implemented the http authentication & http credential apis Change-Id: I7d76504f5909b4354dbe1bc8410f0755458f3eda Signed-off-by: pradeep kumar B --- diff --git a/include/http.h b/include/http.h index a4a4318..10158c0 100644 --- a/include/http.h +++ b/include/http.h @@ -176,6 +176,21 @@ typedef enum { HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED = 505 /**< The status code: 505 HTTP Version Not Supported */ } http_status_code_e; +/** + * @brief Enumeration for the http authentication schemes. + * @since_tizen 3.0 + */ +typedef enum { + HTTP_AUTH_NONE = 0, /**< No authentication type */ + HTTP_AUTH_PROXY_BASIC = 1, /**< The authentication type is Proxy Basic Authentication */ + HTTP_AUTH_PROXY_MD5 = 2, /**< The authentication type is Proxy Digest Authentication */ + HTTP_AUTH_WWW_BASIC = 3, /**< The authentication Type is HTTP Basic Authentication */ + HTTP_AUTH_WWW_MD5 = 4, /**< The authentication type is HTTP Digest Authentication */ + HTTP_AUTH_PROXY_NTLM = 5, /**< The authentication type is Proxy NTLM Authentication */ + HTTP_AUTH_WWW_NTLM = 7, /**< The authentication type is NTLM Authentication */ + HTTP_AUTH_WWW_NEGOTIATE = 8 /**< The authentication type is Negotiate Authentication */ +} http_auth_scheme_e; + /** * @brief Called when the http header is received. * @since_tizen 3.0 @@ -379,7 +394,7 @@ int http_session_get_active_transaction_count(http_session_h http_session, int * */ int http_session_get_max_transaction_count(http_session_h http_session, int *transaction_count); -/* +/** * @brief Destroys all transaction. * @since_tizen 3.0 * @remarks All http_transactions should be set to NULL after using it @@ -431,7 +446,7 @@ int http_transaction_submit(http_transaction_h http_transaction); */ int http_transaction_destroy(http_transaction_h http_transaction); -/* +/** * @brief Registers callback called when receive header. * @since_tizen 3.0 * @param[in] http_transaction The http transaction handle @@ -445,7 +460,7 @@ int http_transaction_destroy(http_transaction_h http_transaction); */ int http_transaction_set_received_header_cb(http_transaction_h http_transaction, http_transaction_header_cb header_cb, void* user_data); -/* +/** * @brief Registers callback called when receive body. * @since_tizen 3.0 * @param[in] http_transaction The http transaction handle @@ -459,7 +474,7 @@ int http_transaction_set_received_header_cb(http_transaction_h http_transaction, */ int http_transaction_set_received_body_cb(http_transaction_h http_transaction, http_transaction_body_cb body_cb, void* user_data); -/* +/** * @brief Registers callback called when write data. * @since_tizen 3.0 * @param[in] http_transaction The http transaction handle @@ -473,7 +488,7 @@ int http_transaction_set_received_body_cb(http_transaction_h http_transaction, h */ int http_transaction_set_uploaded_cb(http_transaction_h http_transaction, http_transaction_write_cb write_cb, void* user_data); -/* +/** * @brief Registers callback called when transaction is completed. * @since_tizen 3.0 * @param[in] http_transaction The http transaction handle @@ -487,11 +502,11 @@ int http_transaction_set_uploaded_cb(http_transaction_h http_transaction, http_t */ int http_transaction_set_completed_cb(http_transaction_h http_transaction, http_transaction_completed_cb completed_cb, void* user_data); -/* +/** * @brief Registers callback called when transaction is aborted. * @since_tizen 3.0 * @param[in] http_transaction The http transaction handle - * @param[in] header_cb The callback function to be called + * @param[in] aborted_cb The callback function to be called * @param[in] user_data The user data passed to the callback function * @return 0 on success, otherwise negative error value * @retval #HTTP_ERROR_NONE Successful @@ -501,7 +516,6 @@ int http_transaction_set_completed_cb(http_transaction_h http_transaction, http_ */ int http_transaction_set_aborted_cb(http_transaction_h http_http_transaction, http_transaction_aborted_cb aborted_cb, void* user_data); - /** * @brief Registers the progress callbacks. * @details Registers callback that is called when data is uploaded/downloaded. @@ -683,6 +697,92 @@ int http_transaction_header_remove_field(http_transaction_h http_transaction, co */ int http_transaction_header_get_field_value(http_transaction_h http_transaction, const char *field_name, char **field_value); +/** + * @brief Opens Http transaction with authentication information. + * @since_tizen 3.0 + * @remarks The @a http_transaction should be released using http_transaction_destroy(). + * @param[in] http_transaction The http transaction handle + * @param[out] http_auth_transaction The http transaction handle + * @return 0 on success, otherwise negative error value + * @retval #HTTP_ERROR_NONE Successful + * @retval #HTTP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HTTP_ERROR_INVALID_OPERATION Invalid operation + * @retval #HTTP_ERROR_OUT_OF_MEMORY Out of memory + * @retval #HTTP_ERROR_NOT_SUPPORTED Not Supported + */ +int http_open_authentication(http_transaction_h http_transaction, http_transaction_h *http_auth_transaction); + +/** + * @brief Sets an HTTP crendentials. + * @details Set an HTTP authentication scheme such as username and password. + * @since_tizen 3.0 + * @param[in] http_transaction The http transaction handle + * @param[in] user_name The http user name + * @param[in] password The http password + * @return 0 on success, otherwise negative error value + * @retval #HTTP_ERROR_NONE Successful + * @retval #HTTP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HTTP_ERROR_NOT_SUPPORTED Not Supported + */ +int http_transaction_set_credentials(http_transaction_h http_transaction, const char *user_name, const char *password); + +/** + * @brief Gets the username & password for the http credential. + * @since_tizen 3.0 + * @remarks The @a user_name & password should be freed using free(). + * @param[in] http_transaction The http transaction handle + * @param[out] user_name The http credential user name + * @param[out] password The http credential password + * @return 0 on success, otherwise negative error value + * @retval #HTTP_ERROR_NONE Successful + * @retval #HTTP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HTTP_ERROR_INVALID_OPERATION Invalid operation + * @retval #HTTP_ERROR_OUT_OF_MEMORY Out of memory + * @retval #HTTP_ERROR_NOT_SUPPORTED Not Supported + */ +int http_transaction_get_credentials(http_transaction_h http_transaction, char **user_name, char **password); + +/** + * @brief Sets an HTTP authentication scheme. + * @details Set an HTTP authentication scheme such as BASIC, MD5, NTLM and etc. + * @since_tizen 3.0 + * @param[in] http_transaction The http transaction handle + * @param[in] auth_scheme The http authentication scheme + * @return 0 on success, otherwise negative error value + * @retval #HTTP_ERROR_NONE Successful + * @retval #HTTP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HTTP_ERROR_NOT_SUPPORTED Not Supported + */ +int http_transaction_set_http_auth_scheme(http_transaction_h http_transaction, http_auth_scheme_e auth_scheme); + +/** + * @brief Gets the Http authentication scheme. + * @since_tizen 3.0 + * @param[in] http_transaction The http transaction handle + * @param[out] auth_scheme The http auth scheme value + * @return 0 on success, otherwise negative error value + * @retval #HTTP_ERROR_NONE Successful + * @retval #HTTP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HTTP_ERROR_INVALID_OPERATION Invalid operation + * @retval #HTTP_ERROR_NOT_SUPPORTED Not Supported + */ +int http_transaction_get_http_auth_scheme(http_transaction_h http_transaction, http_auth_scheme_e *auth_scheme); + +/** + * @brief Gets the Http authentication realm. + * @since_tizen 3.0 + * @remarks The @a realm should be freed using free(). + * @param[in] http_transaction The http transaction handle + * @param[out] realm The http realm value + * @return 0 on success, otherwise negative error value + * @retval #HTTP_ERROR_NONE Successful + * @retval #HTTP_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #HTTP_ERROR_INVALID_OPERATION Invalid operation + * @retval #HTTP_ERROR_OUT_OF_MEMORY Out of memory + * @retval #HTTP_ERROR_NOT_SUPPORTED Not Supported + */ +int http_transaction_get_realm(http_transaction_h http_transaction, char **realm); + /** * @} */ @@ -837,7 +937,7 @@ int http_transaction_request_get_cookie(http_transaction_h http_transaction, con /** * @brief Writes the request message body. * @details This function writes the request message body in the internal queue. \n - * The written queue for request body is uploaded after invoking http_transaction_submit() + * The written queue for request body is uploaded after invoking http_transaction_submit() * @since_tizen 3.0 * @param[in] http_transaction The http transaction handle * @param[in] body The message body data diff --git a/include/http_private.h b/include/http_private.h index f0e26fa..7b8b43b 100644 --- a/include/http_private.h +++ b/include/http_private.h @@ -89,9 +89,24 @@ static const int _HTTP_DEFAULT_HEADER_SIZE = 1024; static const int _MAX_HTTP_TRANSACTIONS_PER_SESSION_NORMAL = 1; static const int _MAX_HTTP_TRANSACTIONS_PER_SESSION_PIPE = 5; + +#define _HTTP_PROXY_AUTHENTICATE_HEADER_NAME "Proxy-Authenticate" +#define _HTTP_WWW_AUTHENTICATE_HEADER_NAME "WWW-Authenticate" +#define _HTTP_CONTENT_LENGTH_HEADER_NAME "Content-Length" + +typedef enum { + _CURL_HTTP_AUTH_NONE = 0, //none + _CURL_HTTP_AUTH_BASIC = 1, // The constant for basic authentication + _CURL_HTTP_AUTH_DIGEST = 2, // The constant for digest authentication + _CURL_HTTP_AUTH_GSSNEGOTIATE = 4, // The constant for gss-negotiate authentication + _CURL_HTTP_AUTH_NTLM = 8 // The constant for ntlm authentication +} curl_http_auth_scheme_e; + typedef struct { struct curl_slist *header_list; GHashTable *hash_table; + gchar *rsp_header; + gint rsp_header_len; } __http_header_h; typedef struct { @@ -131,12 +146,22 @@ typedef struct { gchar *ca_path; gchar error[CURL_ERROR_SIZE]; + /*Authentication Info*/ + bool auth_required; + bool proxy_auth_type; + http_auth_scheme_e auth_scheme; + gchar* realm; + /*Credential Info*/ + gchar* user_name; + gchar* password; + int socket_fd; /*Transaction Callbacks and User data*/ http_transaction_progress_cb progress_cb; void* progress_user_data; http_transaction_header_cb header_cb; void* header_user_data; + bool header_event; http_transaction_body_cb body_cb; void* body_user_data; http_transaction_write_cb write_cb; @@ -174,13 +199,16 @@ gchar* _get_proxy(); struct curl_slist* _get_header_list(http_transaction_h http_transaction); int _get_request_body_size(http_transaction_h http_transaction, int *body_size); -int _read_request_body(http_transaction_h http_transaction, char **body); -void __parse_response_header(char *buffer, size_t written, gpointer user_data); +int _read_request_body(http_transaction_h http_transaction, gchar **body); +void __parse_response_header(gchar *buffer, size_t written, gpointer user_data); int _generate_session_id(void); int _generate_transaction_id(void); void _add_transaction_to_list(http_transaction_h http_transaction); void _remove_transaction_from_list(http_transaction_h http_transaction); void _remove_transaction_list(void); +curl_http_auth_scheme_e _get_http_curl_auth_scheme(http_auth_scheme_e auth_scheme); +http_auth_scheme_e _get_http_auth_scheme(bool proxy_auth, curl_http_auth_scheme_e curl_auth_scheme); +gchar* parse_values(const gchar* string, int from_index, int to_index); #ifdef __cplusplus } diff --git a/src/http_common.c b/src/http_common.c index d363473..e8e044e 100644 --- a/src/http_common.c +++ b/src/http_common.c @@ -106,9 +106,83 @@ gchar* _get_http_method(http_method_e method) return http_method; } +http_auth_scheme_e _get_http_auth_scheme(bool proxy_auth, curl_http_auth_scheme_e curl_auth_scheme) +{ + http_auth_scheme_e auth_scheme = HTTP_AUTH_NONE; + if (proxy_auth) { + switch (curl_auth_scheme) { + case _CURL_HTTP_AUTH_NONE: + auth_scheme = HTTP_AUTH_NONE; + break; + case _CURL_HTTP_AUTH_BASIC: + auth_scheme = HTTP_AUTH_PROXY_BASIC; + break; + case _CURL_HTTP_AUTH_DIGEST: + auth_scheme = HTTP_AUTH_PROXY_MD5; + break; + case _CURL_HTTP_AUTH_NTLM: + auth_scheme = HTTP_AUTH_PROXY_NTLM; + break; + default: + auth_scheme = HTTP_AUTH_NONE; + break; + } + } else { + switch (curl_auth_scheme) { + case _CURL_HTTP_AUTH_NONE: + auth_scheme = HTTP_AUTH_NONE; + break; + case _CURL_HTTP_AUTH_BASIC: + auth_scheme = HTTP_AUTH_WWW_BASIC; + break; + case _CURL_HTTP_AUTH_DIGEST: + auth_scheme = HTTP_AUTH_WWW_MD5; + break; + case _CURL_HTTP_AUTH_NTLM: + auth_scheme = HTTP_AUTH_WWW_NTLM; + break; + case _CURL_HTTP_AUTH_GSSNEGOTIATE: + auth_scheme = HTTP_AUTH_WWW_NEGOTIATE; + break; + default: + auth_scheme = HTTP_AUTH_NONE; + break; + } + } + + return auth_scheme; +} + +curl_http_auth_scheme_e _get_http_curl_auth_scheme(http_auth_scheme_e auth_scheme) +{ + curl_http_auth_scheme_e curl_auth_scheme = _CURL_HTTP_AUTH_NONE; + switch (auth_scheme) { + case HTTP_AUTH_PROXY_BASIC: + case HTTP_AUTH_WWW_BASIC: + curl_auth_scheme = _CURL_HTTP_AUTH_BASIC; + break; + case HTTP_AUTH_PROXY_MD5: + case HTTP_AUTH_WWW_MD5: + curl_auth_scheme = _CURL_HTTP_AUTH_DIGEST; + break; + case HTTP_AUTH_PROXY_NTLM: + case HTTP_AUTH_WWW_NTLM: + curl_auth_scheme = _CURL_HTTP_AUTH_NTLM; + break; + case HTTP_AUTH_WWW_NEGOTIATE: + curl_auth_scheme = _CURL_HTTP_AUTH_GSSNEGOTIATE; + break; + default: + curl_auth_scheme = _CURL_HTTP_AUTH_NONE; + break; + } + + return curl_auth_scheme; +} + void print_curl_multi_errorCode(CURLMcode code) { - const char* message = NULL; + const gchar* message = NULL; switch (code) { case CURLM_CALL_MULTI_PERFORM: message = "CURLM_CALL_MULTI_PERFORM"; @@ -142,6 +216,20 @@ void print_curl_multi_errorCode(CURLMcode code) DBG("CURLMcode(%d): %s", code, message); } +gchar* parse_values(const gchar* string, int from_index, int to_index) +{ + gchar* str = NULL; + int cur_index = to_index - from_index; + + str = (gchar*) malloc(cur_index + 1); + memset(str, '\0', cur_index + 1); + + strncpy(str, (string + from_index), cur_index); + str[cur_index] = '\0'; + + return str; +} + gchar* _get_proxy() { connection_h connection = NULL; diff --git a/src/http_response.c b/src/http_response.c index 03e9558..29671ef 100644 --- a/src/http_response.c +++ b/src/http_response.c @@ -19,7 +19,7 @@ #include "http.h" #include "http_private.h" -static int __convert_status_code(char *status_code) +static int __convert_status_code(gchar *status_code) { int i = 0; int converted_digit = 0; @@ -33,14 +33,14 @@ static int __convert_status_code(char *status_code) return converted_status_code; } -void __parse_response_header(char *buffer, size_t written, gpointer user_data) +void __parse_response_header(gchar *buffer, size_t written, gpointer user_data) { __http_transaction_h* transaction = (__http_transaction_h *)user_data; __http_response_h*response = (__http_response_h *)transaction->response; - char status_code[HTTP_STATUS_CODE_SIZE] = {0, }; - char* start = NULL; - char* end = NULL; + gchar status_code[HTTP_STATUS_CODE_SIZE] = {0, }; + gchar* start = NULL; + gchar* end = NULL; if (strncmp(buffer, "HTTP/", HTTP_PREFIX_SIZE) == 0) { if (strncmp(buffer + HTTP_PREFIX_SIZE, "1.0", HTTP_VERSION_SIZE) == 0) @@ -60,7 +60,26 @@ void __parse_response_header(char *buffer, size_t written, gpointer user_data) response->status_code = __convert_status_code(status_code); response->status_text = g_strndup(start, end - start); - DBG("[Seonah] reason_pharse: %s", response->status_text); + DBG("reason_pharse: %s", response->status_text); + } else { + gchar *field_name = NULL; + gchar *field_value = NULL; + gchar *curpos = NULL; + int pos = 0, len = 0; + + len = strlen(buffer); + curpos = strchr(buffer, ':'); + if (curpos == NULL) + return; + + pos = curpos - buffer + 1; + + field_name = parse_values(buffer, 0, pos - 1); + field_value = parse_values(buffer, pos + 1, len); + + http_transaction_header_add_field(transaction, field_name, field_value); + free(field_name); + free(field_value); } } diff --git a/src/http_session.c b/src/http_session.c index 6b0e2b3..dcd6692 100644 --- a/src/http_session.c +++ b/src/http_session.c @@ -41,8 +41,33 @@ void _check_curl_multi_status(gpointer user_data) switch (curl_code) { case CURLE_OK: - if (transaction->completed_cb) + + if (transaction->completed_cb) { + long http_auth = _CURL_HTTP_AUTH_NONE; + long proxy_auth = _CURL_HTTP_AUTH_NONE; + http_status_code_e status = 0; + bool auth_req = FALSE; + bool proxy = FALSE; + + http_transaction_response_get_status_code(transaction, &status); + DBG("Status(%d)\n", status); + + if (status == HTTP_STATUS_UNAUTHORIZED || status == HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED) { + + transaction->auth_required = auth_req = TRUE; + + curl_easy_getinfo(transaction->easy_handle, CURLINFO_HTTPAUTH_AVAIL, &http_auth); + curl_easy_getinfo(transaction->easy_handle, CURLINFO_PROXYAUTH_AVAIL, &proxy_auth); + + if (proxy_auth != _CURL_HTTP_AUTH_NONE) + proxy = TRUE; + + http_auth_scheme_e auth_scheme = _get_http_auth_scheme(proxy, http_auth); + http_transaction_set_http_auth_scheme(transaction, auth_scheme); + } transaction->completed_cb(transaction, transaction->completed_user_data); + } + break; case CURLE_COULDNT_RESOLVE_HOST: if (transaction->aborted_cb) @@ -64,9 +89,8 @@ void _check_curl_multi_status(gpointer user_data) break; } - if (session->multi_handle != NULL && curl_easy != NULL) { + if (session->multi_handle != NULL && curl_easy != NULL) curl_multi_remove_handle(session->multi_handle, curl_easy); - } } message = curl_multi_info_read(session->multi_handle, &count); } @@ -197,7 +221,7 @@ int __handle_socket_cb(CURL *curl_easy, curl_socket_t fd, int action, void *user static const char *actionstr[] = { "none", "IN", "OUT", "INOUT", "REMOVE"}; - DBG("__handle_socket_cb: fd=%d easy_handle=%p action=%s ", fd, curl_easy, actionstr[action]); + DBG("__handle_socket_cb: fd=%d easy_handle=%p action=%s", fd, curl_easy, actionstr[action]); if (action == CURL_POLL_REMOVE) { DBG("CURL_POLL_REMOVE\n"); _remove_socket_info(sock_info); diff --git a/src/http_transaction.c b/src/http_transaction.c index 2639459..b1962bd 100644 --- a/src/http_transaction.c +++ b/src/http_transaction.c @@ -50,28 +50,49 @@ curl_socket_t __handle_opensocket_cb(void *client_fd, curlsocktype purpose, stru return fd; } -size_t __handle_header_cb(char *buffer, size_t size, size_t nmemb, gpointer user_data) +size_t __handle_header_cb(gchar *buffer, size_t size, size_t nmemb, gpointer user_data) { __http_transaction_h *transaction = (__http_transaction_h *)user_data; + __http_header_h *header = transaction->header; + + gchar *temp_header = NULL; size_t written = size * nmemb; + size_t new_len = header->rsp_header_len + written; + + temp_header = header->rsp_header; + header->rsp_header = realloc(header->rsp_header, new_len + 1); + if (header->rsp_header == NULL) { + free(temp_header); + ERR("realloc() failed\n"); + return -1; + } + + memcpy(header->rsp_header + header->rsp_header_len, buffer, written); + header->rsp_header[new_len] = '\0'; + header->rsp_header_len = new_len; __parse_response_header(buffer, written, user_data); - transaction->header_cb(transaction, buffer, written, transaction->header_user_data); return written; } -size_t __handle_body_cb(char *ptr, size_t size, size_t nmemb, gpointer user_data) +size_t __handle_body_cb(gchar *ptr, size_t size, size_t nmemb, gpointer user_data) { __http_transaction_h *transaction = (__http_transaction_h *)user_data; + __http_header_h *header = transaction->header; size_t written = size * nmemb; + if (!transaction->header_event) { + transaction->header_event = TRUE; + transaction->header_cb(transaction, header->rsp_header, header->rsp_header_len, transaction->header_user_data); + } + transaction->body_cb(transaction, ptr, size, nmemb, transaction->body_user_data); return written; } -size_t __handle_write_cb(char *ptr, size_t size, size_t nmemb, gpointer user_data) +size_t __handle_write_cb(gchar *ptr, size_t size, size_t nmemb, gpointer user_data) { __http_transaction_h *transaction = (__http_transaction_h *)user_data; __http_request_h *request = transaction->request; @@ -90,7 +111,7 @@ size_t __handle_write_cb(char *ptr, size_t size, size_t nmemb, gpointer user_dat return body_size; } -size_t __http_debug_received(CURL* easy_handle, curl_infotype type, char* byte, size_t size, void *user_data) +size_t __http_debug_received(CURL* easy_handle, curl_infotype type, gchar* byte, size_t size, void *user_data) { char log_buffer[_HTTP_DEFAULT_HEADER_SIZE]; int log_size = 0; @@ -118,6 +139,42 @@ size_t __http_debug_received(CURL* easy_handle, curl_infotype type, char* byte, return 0; } +int http_transaction_set_authentication_info(http_transaction_h http_transaction) +{ + _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(http_transaction) is NULL\n"); + + __http_transaction_h *transaction = (__http_transaction_h *)http_transaction; + + http_auth_scheme_e auth_scheme = HTTP_AUTH_NONE; + + http_transaction_get_http_auth_scheme(transaction, &auth_scheme); + + switch (auth_scheme) { + case HTTP_AUTH_PROXY_BASIC: + case HTTP_AUTH_PROXY_MD5: + case HTTP_AUTH_PROXY_NTLM: + http_transaction_header_get_field_value(transaction, _HTTP_PROXY_AUTHENTICATE_HEADER_NAME, &transaction->realm); + + transaction->proxy_auth_type = TRUE; + break; + + case HTTP_AUTH_WWW_BASIC: + case HTTP_AUTH_WWW_MD5: + case HTTP_AUTH_WWW_NEGOTIATE: + case HTTP_AUTH_WWW_NTLM: + http_transaction_header_get_field_value(transaction, _HTTP_WWW_AUTHENTICATE_HEADER_NAME, &transaction->realm); + + transaction->proxy_auth_type = FALSE; + break; + + default: + break; + } + + return HTTP_ERROR_NONE; +} + int _transaction_submit(gpointer user_data) { __http_transaction_h *transaction = (__http_transaction_h *)user_data; @@ -131,8 +188,10 @@ int _transaction_submit(gpointer user_data) gboolean write_event = FALSE; gint body_size = 0; gint content_len = 0; + http_auth_scheme_e auth_scheme = HTTP_AUTH_NONE; - transaction->easy_handle = curl_easy_init(); + if (!transaction->easy_handle) + transaction->easy_handle = curl_easy_init(); if (request->http_version == HTTP_VERSION_1_0) curl_easy_setopt(transaction->easy_handle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); @@ -198,6 +257,36 @@ int _transaction_submit(gpointer user_data) DBG("Disabled Auto-Redirection\n"); } + /* Authentication */ + if (transaction->auth_required) { + + curl_http_auth_scheme_e curl_auth_scheme; + gchar *user_name = NULL; + gchar *password = NULL; + gchar *credentials = NULL; + + http_transaction_get_credentials(transaction, &user_name, &password); + credentials = (gchar *)malloc(sizeof(gchar) * (strlen(user_name) + 1 + strlen(password) + 1)); + sprintf(credentials, "%s:%s", (gchar*)user_name, (gchar*)password); + free(user_name); + free(password); + + http_transaction_get_http_auth_scheme(transaction, &auth_scheme); + + curl_auth_scheme = _get_http_curl_auth_scheme(auth_scheme); + + if (transaction->proxy_auth_type) { + + curl_easy_setopt(transaction->easy_handle, CURLOPT_PROXYAUTH, curl_auth_scheme); + curl_easy_setopt(transaction->easy_handle, CURLOPT_PROXYUSERPWD, credentials); + + } else { + curl_easy_setopt(transaction->easy_handle, CURLOPT_HTTPAUTH, curl_auth_scheme); + curl_easy_setopt(transaction->easy_handle, CURLOPT_USERPWD, credentials); + } + free(credentials); + } + curl_easy_setopt(transaction->easy_handle, CURLOPT_HEADERFUNCTION, __handle_header_cb); curl_easy_setopt(transaction->easy_handle, CURLOPT_HEADERDATA, transaction); @@ -300,6 +389,13 @@ API int http_session_open_transaction(http_session_h http_session, http_method_e transaction->ca_path = g_strdup(HTTP_DEFAULT_CA_PATH); transaction->error[0] = '\0'; + transaction->auth_required = FALSE; + transaction->realm = NULL; + transaction->user_name = NULL; + transaction->password = NULL; + transaction->proxy_auth_type = FALSE; + transaction->auth_scheme = HTTP_AUTH_NONE; + transaction->header_cb = NULL; transaction->body_cb = NULL; transaction->write_cb = NULL; @@ -329,6 +425,11 @@ API int http_session_open_transaction(http_session_h http_session, http_method_e return HTTP_ERROR_OUT_OF_MEMORY; } + transaction->header->rsp_header_len = 0; + transaction->header->rsp_header = malloc(transaction->header->rsp_header_len + 1); + transaction->header->rsp_header[0] = '\0'; + transaction->header_event = FALSE; + transaction->request->host_uri = NULL; transaction->request->method = _get_http_method(method); transaction->request->encoding = NULL; @@ -409,6 +510,25 @@ API int http_transaction_destroy(http_transaction_h http_transaction) } transaction->error[0] = '\0'; + if (transaction->user_name) { + free(transaction->user_name); + transaction->user_name = NULL; + } + + if (transaction->password) { + free(transaction->password); + transaction->password = NULL; + } + + if (transaction->realm) { + free(transaction->realm); + transaction->realm = NULL; + } + + transaction->auth_required = FALSE; + transaction->proxy_auth_type = FALSE; + transaction->auth_scheme = HTTP_AUTH_NONE; + transaction->header_cb = NULL; transaction->body_cb = NULL; transaction->write_cb = NULL; @@ -461,10 +581,18 @@ API int http_transaction_destroy(http_transaction_h http_transaction) } if (header->hash_table != NULL) { + + g_hash_table_remove_all(header->hash_table); + g_hash_table_destroy(header->hash_table); header->hash_table = NULL; } + if (header->rsp_header != NULL) { + free(header->rsp_header); + header->rsp_header = NULL; + header->rsp_header_len = 0; + } free(header); } @@ -778,3 +906,199 @@ API int http_session_destroy_all_transactions(http_session_h http_session) return HTTP_ERROR_NONE; } +API int http_transaction_set_http_auth_scheme(http_transaction_h http_transaction, http_auth_scheme_e auth_scheme) +{ + _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(http_transaction) is NULL\n"); + + __http_transaction_h *transaction = (__http_transaction_h *)http_transaction; + + transaction->auth_scheme = auth_scheme; + + return HTTP_ERROR_NONE; +} + +API int http_transaction_get_http_auth_scheme(http_transaction_h http_transaction, http_auth_scheme_e *auth_scheme) +{ + _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(http_transaction) is NULL\n"); + _retvm_if(auth_scheme == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(auth_scheme) is NULL\n"); + + __http_transaction_h *transaction = (__http_transaction_h *)http_transaction; + + *auth_scheme = transaction->auth_scheme; + + return HTTP_ERROR_NONE; +} + +API int http_transaction_get_realm(http_transaction_h http_transaction, char **realm) +{ + _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(http_transaction) is NULL\n"); + _retvm_if(realm == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(realm) is NULL\n"); + + __http_transaction_h *transaction = (__http_transaction_h *)http_transaction; + + *realm = g_strdup(transaction->realm); + if (*realm == NULL) { + ERR("strdup is failed\n"); + return HTTP_ERROR_OUT_OF_MEMORY; + } + + return HTTP_ERROR_NONE; +} + +API int http_transaction_set_credentials(http_transaction_h http_transaction, const char *user_name, const char *password) +{ + _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(http_transaction) is NULL\n"); + _retvm_if(user_name == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(user_name) is NULL\n"); + _retvm_if(password == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(password) is NULL\n"); + + __http_transaction_h *transaction = (__http_transaction_h *)http_transaction; + + transaction->user_name = g_strdup(user_name); + transaction->password = g_strdup(password); + + return HTTP_ERROR_NONE; +} + +API int http_transaction_get_credentials(http_transaction_h http_transaction, char **user_name, char **password) +{ + _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(http_transaction) is NULL\n"); + _retvm_if(user_name == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(user_name) is NULL\n"); + _retvm_if(password == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(password) is NULL\n"); + + __http_transaction_h *transaction = (__http_transaction_h *)http_transaction; + + *user_name = g_strdup(transaction->user_name); + if (*user_name == NULL) { + ERR("strdup is failed\n"); + return HTTP_ERROR_OUT_OF_MEMORY; + } + + *password = g_strdup(transaction->password); + if (*password == NULL) { + ERR("strdup is failed\n"); + return HTTP_ERROR_OUT_OF_MEMORY; + } + return HTTP_ERROR_NONE; +} + +API int http_open_authentication(http_transaction_h http_transaction, http_transaction_h *http_auth_transaction) +{ + _retvm_if(http_transaction == NULL, HTTP_ERROR_INVALID_PARAMETER, + "parameter(http_transaction) is NULL\n"); + + __http_transaction_h *transaction = (__http_transaction_h *)http_transaction; + __http_transaction_h *auth_transaction = NULL; + + auth_transaction = (__http_transaction_h *)malloc(sizeof(__http_transaction_h)); + if (auth_transaction == NULL) { + ERR("Fail to allocate transaction memory!!"); + return HTTP_ERROR_OUT_OF_MEMORY; + } + + auth_transaction->easy_handle = NULL; + auth_transaction->interface_name = NULL; + auth_transaction->ca_path = NULL; + auth_transaction->error[0] = '\0'; + + if (transaction->interface_name) + auth_transaction->interface_name = g_strdup(transaction->interface_name); + auth_transaction->timeout = 0; + auth_transaction->verify_peer = transaction->verify_peer; + if (transaction->ca_path) + auth_transaction->ca_path = g_strdup(transaction->ca_path); + + auth_transaction->auth_required = transaction->auth_required; + auth_transaction->realm = NULL; + auth_transaction->user_name = NULL; + auth_transaction->password = NULL; + auth_transaction->proxy_auth_type = FALSE; + auth_transaction->auth_scheme = transaction->auth_scheme; + auth_transaction->write_event = FALSE; + + auth_transaction->header_cb = NULL; + auth_transaction->header_user_data = NULL; + auth_transaction->body_cb = NULL; + auth_transaction->body_user_data = NULL; + auth_transaction->write_cb = NULL; + auth_transaction->write_user_data = NULL; + auth_transaction->completed_cb = NULL; + auth_transaction->completed_user_data = NULL; + auth_transaction->aborted_cb = NULL; + auth_transaction->progress_cb = NULL; + auth_transaction->progress_user_data = NULL; + + auth_transaction->session = transaction->session; + auth_transaction->session->active_transaction_count = transaction->session->active_transaction_count; + auth_transaction->session_id = transaction->session_id; + + auth_transaction->request = (__http_request_h *)malloc(sizeof(__http_request_h)); + if (auth_transaction->request == NULL) { + free(auth_transaction->interface_name); + free(auth_transaction->ca_path); + free(auth_transaction); + ERR("Fail to allocate request memory!!"); + return HTTP_ERROR_OUT_OF_MEMORY; + } + + auth_transaction->request->host_uri = NULL; + auth_transaction->request->method = NULL; + + auth_transaction->response = (__http_response_h *)malloc(sizeof(__http_response_h)); + if (auth_transaction->response == NULL) { + free(auth_transaction->interface_name); + free(auth_transaction->ca_path); + free(auth_transaction->request); + free(auth_transaction); + ERR("Fail to allocate response memory!!"); + return HTTP_ERROR_OUT_OF_MEMORY; + } + + auth_transaction->header = (__http_header_h *)malloc(sizeof(__http_header_h)); + if (auth_transaction->header == NULL) { + free(auth_transaction->interface_name); + free(auth_transaction->ca_path); + free(auth_transaction->request); + free(auth_transaction->response); + free(auth_transaction); + ERR("Fail to allocate header memory!!"); + return HTTP_ERROR_OUT_OF_MEMORY; + } + + auth_transaction->header->rsp_header_len = 0; + auth_transaction->header->rsp_header = malloc(auth_transaction->header->rsp_header_len + 1); + auth_transaction->header->rsp_header[0] = '\0'; + auth_transaction->header_event = FALSE; + + if (transaction->request->host_uri) + auth_transaction->request->host_uri = g_strdup(transaction->request->host_uri); + if (transaction->request->method) + auth_transaction->request->method = g_strdup(transaction->request->method); + auth_transaction->request->encoding = NULL; + auth_transaction->request->cookie = NULL; + auth_transaction->request->http_version = HTTP_VERSION_1_1; + auth_transaction->request->body_queue = g_queue_new(); + auth_transaction->request->tot_size = 0; + + auth_transaction->header->header_list = NULL; + auth_transaction->header->hash_table = NULL; + + auth_transaction->thread = NULL; + + *http_auth_transaction = (http_transaction_h)auth_transaction; + _add_transaction_to_list(auth_transaction); + + http_transaction_set_authentication_info((http_transaction_h)auth_transaction); + + return HTTP_ERROR_NONE; +} diff --git a/test/http_test.c b/test/http_test.c index 32e1d27..a6b5927 100644 --- a/test/http_test.c +++ b/test/http_test.c @@ -31,6 +31,7 @@ FILE* fp1 = NULL; FILE* fp2 = NULL; http_session_h session = NULL; +void _register_callbacks(http_transaction_h transaction); void __transaction_header_cb(http_transaction_h transaction, char *header, size_t header_len, void *user_data) { @@ -57,12 +58,31 @@ void __transaction_completed_cb(http_transaction_h transaction, void *user_data) http_status_code_e status = 0; int ret; char *uri = NULL; + char id[16] = {0, }; + char pw[16] = {0, }; ret = http_transaction_request_get_uri(transaction, &uri); ret = http_transaction_response_get_status_code(transaction, &status); + DBG("%s - status(%d)\n", uri, status); + if (status == HTTP_STATUS_UNAUTHORIZED) { + DBG("Authentication Required\n"); + http_transaction_h http_auth_transaction; + http_auth_scheme_e auth_scheme = HTTP_AUTH_NONE; + + http_open_authentication(transaction, &http_auth_transaction); + http_transaction_get_http_auth_scheme(http_auth_transaction, &auth_scheme); + + printf("User ID: "); + ret = scanf("%15s", id); + printf("Password: "); + ret = scanf("%15s", pw); + + http_transaction_set_credentials(http_auth_transaction, id, pw); + _register_callbacks(http_auth_transaction); + http_transaction_submit(http_auth_transaction); + } http_transaction_header_remove_field(transaction, "Content-Length"); - DBG("%s - status(%d)\n", uri, status); ret = http_transaction_destroy(transaction); if (ret == HTTP_ERROR_NONE) DBG("Success to close transaction\n"); else DBG("Fail to close transaction\n"); @@ -225,6 +245,40 @@ int test_simple_post(void) return 1; } +int test_simple_authentication_get(void) +{ + int ret; + http_transaction_h transaction = NULL; + http_method_e method; + char uri[1024]; + + ret = http_session_open_transaction(session, HTTP_METHOD_GET, &transaction); + if (ret != 0) { + ERR("Fail to open transaction", ret); + return 0; + } + + printf("Input uri for transaction: "); + ret = scanf("%1023s", uri); + + http_transaction_request_get_method(transaction, &method); + ret = http_transaction_request_set_uri(transaction, uri); + if (ret != 0) { + ERR("Fail to set URI", ret); + return 0; + } + + _register_callbacks(transaction); + ret = http_transaction_submit(transaction); + + if (ret != 0) { + ERR("Fail to submit transaction", ret); + return 0; + } + + return 1; +} + gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data) { int rv; @@ -247,7 +301,8 @@ gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data) printf("5 - Simple GET\n"); printf("6 - Multiple GET\n"); printf("7 - Simple POST\n"); - printf("8 - \n"); + printf("8 - Simple Authentication GET\n"); + printf("9 - \n"); printf("0 - Exit \n"); printf("ENTER - Show options menu.......\n"); } @@ -274,6 +329,9 @@ gboolean test_thread(GIOChannel *source, GIOCondition condition, gpointer data) case '7': rv = test_simple_post(); break; + case '8': + rv = test_simple_authentication_get(); + break; } if (rv == 1)