mirror of
https://git.gnunet.org/libmicrohttpd.git
synced 2026-09-25 04:09:31 +03:00
work on test
This commit is contained in:
@@ -26,6 +26,7 @@ $(top_builddir)/src/mhd2/libmicrohttpd2.la: $(top_builddir)/src/mhd2/Makefile
|
||||
|
||||
check_PROGRAMS = \
|
||||
test_client_server \
|
||||
test_authentication \
|
||||
test_postprocessor
|
||||
|
||||
if MHD_ENABLE_HTTPS
|
||||
@@ -56,6 +57,11 @@ test_client_server_SOURCES = \
|
||||
test_client_server_LDADD = \
|
||||
libmhdt.la
|
||||
|
||||
test_authentication_SOURCES = \
|
||||
test_authentication.c
|
||||
test_authentication_LDADD = \
|
||||
libmhdt.la
|
||||
|
||||
test_tls_SOURCES = \
|
||||
test_tls.c
|
||||
test_tls_LDADD = \
|
||||
|
||||
@@ -375,6 +375,34 @@ MHDT_client_do_post (
|
||||
struct MHDT_PhaseContext *pc);
|
||||
|
||||
|
||||
/**
|
||||
* Perform GET request and send some HTTP basic authentication header
|
||||
* to authorize the request.
|
||||
*
|
||||
* @param cls a string with "$USERNAME:$PASSWORD"
|
||||
* @param pc context for the client
|
||||
* @return error message, NULL on success
|
||||
*/
|
||||
const char *
|
||||
MHDT_client_send_basic_auth (
|
||||
const void *cls,
|
||||
struct MHDT_PhaseContext *pc);
|
||||
|
||||
|
||||
/**
|
||||
* Perform GET request and send some HTTP basic authentication header
|
||||
* to authorize the request. Expect authentication to fail.
|
||||
*
|
||||
* @param cls a string with "$USERNAME:$PASSWORD"
|
||||
* @param pc context for the client
|
||||
* @return error message, NULL on success
|
||||
*/
|
||||
const char *
|
||||
MHDT_client_fail_basic_auth (
|
||||
const void *cls,
|
||||
struct MHDT_PhaseContext *pc);
|
||||
|
||||
|
||||
/**
|
||||
* Returns the text from @a cls as the response to any
|
||||
* request.
|
||||
@@ -602,6 +630,35 @@ MHDT_server_reply_check_post (
|
||||
uint_fast64_t upload_size);
|
||||
|
||||
|
||||
/**
|
||||
* Checks that the client request includes the given
|
||||
* username and password in HTTP basic authetnication.
|
||||
* If so, returns #MHD_HTTP_STATUS_NO_CONTENT, otherwise
|
||||
* an #MHD_HTTP_STATUS_UNAUTHORIZED.
|
||||
*
|
||||
* @param cls expected upload data as a 0-terminated string.
|
||||
* @param request the request object
|
||||
* @param path the requested uri (without arguments after "?")
|
||||
* @param method the HTTP method used (#MHD_HTTP_METHOD_GET,
|
||||
* #MHD_HTTP_METHOD_PUT, etc.)
|
||||
* @param upload_size the size of the message upload content payload,
|
||||
* #MHD_SIZE_UNKNOWN for chunked uploads (if the
|
||||
* final chunk has not been processed yet)
|
||||
* @return action how to proceed, NULL
|
||||
* if the request must be aborted due to a serious
|
||||
* error while handling the request (implies closure
|
||||
* of underling data stream, for HTTP/1.1 it means
|
||||
* socket closure).
|
||||
*/
|
||||
const struct MHD_Action *
|
||||
MHDT_server_reply_check_basic_auth (
|
||||
void *cls,
|
||||
struct MHD_Request *MHD_RESTRICT request,
|
||||
const struct MHD_String *MHD_RESTRICT path,
|
||||
enum MHD_HTTP_Method method,
|
||||
uint_fast64_t upload_size);
|
||||
|
||||
|
||||
/**
|
||||
* Initialize options for an MHD daemon for a test.
|
||||
*
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file libtest_convenience.c
|
||||
* @file libtest_convenience_client_request.c
|
||||
* @brief convenience functions implementing clients making requests for libtest users
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
@@ -814,3 +814,114 @@ MHDT_client_do_post (
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send HTTP request with basic authentication.
|
||||
*
|
||||
* @param cred $USERNAME:$PASSWORD to use
|
||||
* @param[in,out] phase context
|
||||
* @param[out] http_status set to HTTP status
|
||||
* @return error message, NULL on success
|
||||
*/
|
||||
static const char *
|
||||
send_basic_auth (const char *cred,
|
||||
struct MHDT_PhaseContext *pc,
|
||||
unsigned int *http_status)
|
||||
{
|
||||
CURL *c;
|
||||
const char *err;
|
||||
long status;
|
||||
char *pass = strchr (cred, ':');
|
||||
char *user;
|
||||
|
||||
if (NULL == pass)
|
||||
return "invalid credential given";
|
||||
user = strndup (cred,
|
||||
pass - user);
|
||||
pass++;
|
||||
c = curl_easy_init ();
|
||||
if (NULL == c)
|
||||
{
|
||||
free (user);
|
||||
return "Failed to initialize Curl handle";
|
||||
}
|
||||
err = set_url (c,
|
||||
pc->base_url,
|
||||
pc);
|
||||
if (NULL != err)
|
||||
{
|
||||
free (user);
|
||||
curl_easy_cleanup (c);
|
||||
return err;
|
||||
}
|
||||
if ( (CURLE_OK !=
|
||||
curl_easy_setopt (c,
|
||||
CURLOPT_HTTPAUTH,
|
||||
(long) CURLAUTH_BASIC)) ||
|
||||
(CURLE_OK !=
|
||||
curl_easy_setopt (c,
|
||||
CURLOPT_USERNAME,
|
||||
"user")) ||
|
||||
(CURLE_OK !=
|
||||
curl_easy_setopt (c,
|
||||
CURLOPT_PASSWORD,
|
||||
"password")) )
|
||||
{
|
||||
curl_easy_cleanup (c);
|
||||
free (user);
|
||||
return "Failed to set basic authentication header for curl request";
|
||||
}
|
||||
free (user);
|
||||
PERFORM_REQUEST (c);
|
||||
if (CURLE_OK !=
|
||||
curl_easy_getinfo (c,
|
||||
CURLINFO_RESPONSE_CODE,
|
||||
&status))
|
||||
{
|
||||
return "Failed to get HTTP status";
|
||||
}
|
||||
*http_status = (unsigned int) status;
|
||||
curl_easy_cleanup (c);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
MHDT_client_send_basic_auth (
|
||||
const void *cls,
|
||||
struct MHDT_PhaseContext *pc)
|
||||
{
|
||||
const char *cred = cls;
|
||||
const char *ret;
|
||||
unsigned int status;
|
||||
|
||||
ret = send_basic_auth (cred,
|
||||
pc,
|
||||
&status);
|
||||
if (NULL != ret)
|
||||
return ret;
|
||||
if (MHD_HTTP_STATUS_NO_CONTENT != status)
|
||||
return "invalid HTTP response code";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const char *
|
||||
MHDT_client_fail_basic_auth (
|
||||
const void *cls,
|
||||
struct MHDT_PhaseContext *pc)
|
||||
{
|
||||
const char *cred = cls;
|
||||
const char *ret;
|
||||
unsigned int status;
|
||||
|
||||
ret = send_basic_auth (cred,
|
||||
pc,
|
||||
&status);
|
||||
if (NULL != ret)
|
||||
return ret;
|
||||
if (MHD_HTTP_STATUS_UNAUTHORIZED != status)
|
||||
return "invalid HTTP response code";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -723,3 +723,69 @@ MHDT_server_reply_check_post (
|
||||
&post_stream_done,
|
||||
pi);
|
||||
}
|
||||
|
||||
|
||||
const struct MHD_Action *
|
||||
MHDT_server_reply_check_basic_auth (
|
||||
void *cls,
|
||||
struct MHD_Request *MHD_RESTRICT request,
|
||||
const struct MHD_String *MHD_RESTRICT path,
|
||||
enum MHD_HTTP_Method method,
|
||||
uint_fast64_t upload_size)
|
||||
{
|
||||
const char *cred = cls;
|
||||
union MHD_RequestInfoDynamicData dd;
|
||||
enum MHD_StatusCode sc;
|
||||
struct MHD_BasicAuthInfo *ba;
|
||||
struct MHD_Connection *connection; // FIXME - suboptimal API
|
||||
union MHD_RequestInfoFixedData rif;
|
||||
|
||||
#define FIXME 1
|
||||
#if FIXME
|
||||
sc = MHD_request_get_info_fixed (request,
|
||||
MHD_REQUEST_INFO_FIXED_CONNECTION,
|
||||
&rif);
|
||||
if (MHD_SC_OK != sc)
|
||||
return NULL;
|
||||
connection = rif.v_connection;
|
||||
#endif
|
||||
/* should not be needed, except to make gcc happy */
|
||||
memset (&dd,
|
||||
0,
|
||||
sizeof (dd));
|
||||
sc = MHD_request_get_info_dynamic (request,
|
||||
MHD_REQUEST_INFO_DYNAMIC_BAUTH_REQ_INFO,
|
||||
&dd);
|
||||
if (MHD_SC_OK != sc)
|
||||
return MHD_action_basic_auth_required_response (
|
||||
connection, // FIXME: I'd like to see 'request' here.
|
||||
"test-realm",
|
||||
MHD_YES,
|
||||
MHD_response_from_empty (
|
||||
MHD_HTTP_STATUS_FORBIDDEN));
|
||||
ba = dd.v_bauth_info;
|
||||
if (NULL == ba)
|
||||
return MHD_action_basic_auth_required_response (
|
||||
connection, // FIXME: I'd like to see 'request' here.
|
||||
"test-realm",
|
||||
MHD_YES,
|
||||
MHD_response_from_empty (
|
||||
MHD_HTTP_STATUS_FORBIDDEN));
|
||||
if ( (0 != strncmp (ba->username.cstr,
|
||||
cred,
|
||||
ba->username.len)) ||
|
||||
(':' != cred[ba->username.len]) ||
|
||||
(NULL == ba->password.cstr) ||
|
||||
(0 != strcmp (ba->password.cstr,
|
||||
&cred[ba->username.len + 1])) )
|
||||
return MHD_action_basic_auth_required_response (
|
||||
connection, // FIXME: I'd like to see 'request' here.
|
||||
"test-realm",
|
||||
MHD_YES,
|
||||
MHD_response_from_empty (
|
||||
MHD_HTTP_STATUS_FORBIDDEN));
|
||||
return MHD_action_from_response (
|
||||
request,
|
||||
MHD_response_from_empty (
|
||||
MHD_HTTP_STATUS_NO_CONTENT));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
This file is part of GNU libmicrohttpd
|
||||
Copyright (C) 2016, 2024 Christian Grothoff & Evgeny Grin (Karlson2k)
|
||||
|
||||
GNU libmicrohttpd is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
GNU libmicrohttpd is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_authentication.c
|
||||
* @brief test for HTTP authentication
|
||||
* @author Christian Grothoff
|
||||
*/
|
||||
#include "libtest.h"
|
||||
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
struct MHD_DaemonOptionAndValue thread1auto[] = {
|
||||
MHD_D_OPTION_POLL_SYSCALL (MHD_SPS_AUTO),
|
||||
MHD_D_OPTION_WM_WORKER_THREADS (1),
|
||||
MHD_D_OPTION_TERMINATE ()
|
||||
};
|
||||
struct ServerType
|
||||
{
|
||||
const char *label;
|
||||
MHDT_ServerSetup server_setup;
|
||||
void *server_setup_cls;
|
||||
MHDT_ServerRunner server_runner;
|
||||
void *server_runner_cls;
|
||||
} configs[] = {
|
||||
{
|
||||
.label = "auto-selected mode, single threaded",
|
||||
.server_setup = &MHDT_server_setup_minimal,
|
||||
.server_setup_cls = thread1auto,
|
||||
.server_runner = &MHDT_server_run_minimal,
|
||||
},
|
||||
{
|
||||
.label = "END"
|
||||
},
|
||||
};
|
||||
struct MHDT_Phase phases[] = {
|
||||
{
|
||||
.label = "simple basic authentication",
|
||||
.server_cb = &MHDT_server_reply_check_basic_auth,
|
||||
.server_cb_cls = (void *) "username:password",
|
||||
.client_cb = &MHDT_client_send_basic_auth,
|
||||
.client_cb_cls = (void *) "username:password",
|
||||
.timeout_ms = 200,
|
||||
},
|
||||
{
|
||||
.label = "failing basic authentication",
|
||||
.server_cb = &MHDT_server_reply_check_basic_auth,
|
||||
.server_cb_cls = (void *) "username:password",
|
||||
.client_cb = &MHDT_client_fail_basic_auth,
|
||||
.client_cb_cls = (void *) "username:word", /* incorrect on purpose */
|
||||
.timeout_ms = 200,
|
||||
},
|
||||
// TODO: digest auth
|
||||
{
|
||||
.label = NULL,
|
||||
},
|
||||
};
|
||||
unsigned int i;
|
||||
|
||||
(void) argc; /* Unused. Silence compiler warning. */
|
||||
(void) argv; /* Unused. Silence compiler warning. */
|
||||
|
||||
for (i = 0; NULL != configs[i].server_setup; i++)
|
||||
{
|
||||
int ret;
|
||||
|
||||
fprintf (stderr,
|
||||
"Running tests with server setup '%s'\n",
|
||||
configs[i].label);
|
||||
ret = MHDT_test (configs[i].server_setup,
|
||||
configs[i].server_setup_cls,
|
||||
configs[i].server_runner,
|
||||
configs[i].server_runner_cls,
|
||||
phases);
|
||||
if (0 != ret)
|
||||
{
|
||||
fprintf (stderr,
|
||||
"Test failed with server of type '%s' (%u)\n",
|
||||
configs[i].label,
|
||||
i);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user