mirror of
https://github.com/samba-team/samba.git
synced 2025-02-28 01:58:17 +03:00
s4:lib/http: add http_[dis]connect_send and recv
Not used for now, that comes later. Signed-off-by: Ralph Boehme <slow@samba.org> Reviewed-by: Samuel Cabrero <scabrero@suse.de>
This commit is contained in:
parent
2a90202052
commit
314043828b
@ -92,6 +92,29 @@ int http_remove_header(struct http_header **, const char *);
|
||||
int http_add_header(TALLOC_CTX *, struct http_header **, const char *, const char *);
|
||||
int http_replace_header(TALLOC_CTX *, struct http_header **, const char *, const char *);
|
||||
|
||||
/* HTTP(s) connect */
|
||||
|
||||
struct http_conn;
|
||||
struct tstream_tls_params;
|
||||
|
||||
struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
const char *http_server,
|
||||
uint16_t http_port,
|
||||
struct cli_credentials *credentials,
|
||||
struct tstream_tls_params *tls_params);
|
||||
int http_connect_recv(struct tevent_req *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct http_conn **http_conn);
|
||||
|
||||
struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct http_conn *http_conn);
|
||||
int http_disconnect_recv(struct tevent_req *req);
|
||||
|
||||
struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn);
|
||||
struct tstream_context *http_conn_tstream(struct http_conn *http_conn);
|
||||
|
||||
/* HTTP request */
|
||||
struct tevent_req *http_send_request_send(TALLOC_CTX *,
|
||||
struct tevent_context *,
|
||||
|
348
source4/lib/http/http_conn.c
Normal file
348
source4/lib/http/http_conn.c
Normal file
@ -0,0 +1,348 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
HTTP library
|
||||
|
||||
Copyright (C) 2019 Ralph Boehme <slow@samba.org>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/util/tevent_ntstatus.h"
|
||||
#include "libcli/dns/dns_lookup.h"
|
||||
#include "lib/tsocket/tsocket.h"
|
||||
#include "lib/util/util_net.h"
|
||||
#include "lib/tls/tls.h"
|
||||
#include "lib/util/tevent_unix.h"
|
||||
#include "http.h"
|
||||
#include "http_internal.h"
|
||||
|
||||
struct http_connect_state {
|
||||
struct tevent_context *ev;
|
||||
const char *http_server;
|
||||
const char *http_server_ip;
|
||||
uint16_t http_port;
|
||||
struct tsocket_address *local_address;
|
||||
struct tsocket_address *remote_address;
|
||||
struct cli_credentials *credentials;
|
||||
struct tstream_tls_params *tls_params;
|
||||
|
||||
struct http_conn *http_conn;
|
||||
};
|
||||
|
||||
static void http_connect_dns_done(struct tevent_req *subreq);
|
||||
static void http_connect_tcp_connect(struct tevent_req *req);
|
||||
static void http_connect_tcp_done(struct tevent_req *subreq);
|
||||
static void http_connect_tls_done(struct tevent_req *subreq);
|
||||
|
||||
struct tevent_req *http_connect_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
const char *http_server,
|
||||
uint16_t http_port,
|
||||
struct cli_credentials *credentials,
|
||||
struct tstream_tls_params *tls_params)
|
||||
{
|
||||
struct tevent_req *req = NULL;
|
||||
struct tevent_req *subreq = NULL;
|
||||
struct http_connect_state *state = NULL;
|
||||
int ret;
|
||||
|
||||
DBG_DEBUG("Connecting to [%s] over HTTP%s\n",
|
||||
http_server, tls_params != NULL ? "S" : "");
|
||||
|
||||
req = tevent_req_create(mem_ctx, &state, struct http_connect_state);
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*state = (struct http_connect_state) {
|
||||
.ev = ev,
|
||||
.http_port = http_port,
|
||||
.credentials = credentials,
|
||||
.tls_params = tls_params,
|
||||
};
|
||||
|
||||
state->http_server = talloc_strdup(state, http_server);
|
||||
if (tevent_req_nomem(state->http_server, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->http_conn = talloc_zero(state, struct http_conn);
|
||||
if (tevent_req_nomem(state->http_conn, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
state->http_conn->send_queue = tevent_queue_create(state->http_conn,
|
||||
"HTTP send queue");
|
||||
if (tevent_req_nomem(state->http_conn->send_queue, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
ret = tsocket_address_inet_from_strings(state,
|
||||
"ip",
|
||||
NULL,
|
||||
0,
|
||||
&state->local_address);
|
||||
if (ret != 0) {
|
||||
tevent_req_error(req, errno);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
if (!is_ipaddress(http_server)) {
|
||||
subreq = dns_lookup_send(state,
|
||||
ev,
|
||||
NULL,
|
||||
http_server,
|
||||
DNS_QCLASS_IN,
|
||||
DNS_QTYPE_A);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
tevent_req_set_callback(subreq, http_connect_dns_done, req);
|
||||
return req;
|
||||
}
|
||||
state->http_server_ip = state->http_server;
|
||||
|
||||
http_connect_tcp_connect(req);
|
||||
if (!tevent_req_is_in_progress(req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void http_connect_dns_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct http_connect_state *state = tevent_req_data(
|
||||
req, struct http_connect_state);
|
||||
struct dns_name_packet *dns_reply = NULL;
|
||||
struct dns_res_rec *an = NULL;
|
||||
uint16_t i;
|
||||
int ret;
|
||||
|
||||
ret = dns_lookup_recv(subreq, state, &dns_reply);
|
||||
TALLOC_FREE(subreq);
|
||||
if (ret != 0) {
|
||||
tevent_req_error(req, ret);
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < dns_reply->ancount; i++) {
|
||||
an = &dns_reply->answers[i];
|
||||
if (an->rr_type == DNS_QTYPE_A) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i >= dns_reply->ancount) {
|
||||
tevent_req_error(req, ENOENT);
|
||||
return;
|
||||
}
|
||||
|
||||
state->http_server_ip = talloc_strdup(state, an->rdata.ipv4_record);
|
||||
if (tevent_req_nomem(state->http_server_ip, req)) {
|
||||
return;
|
||||
}
|
||||
|
||||
return http_connect_tcp_connect(req);
|
||||
}
|
||||
|
||||
static void http_connect_tcp_connect(struct tevent_req *req)
|
||||
{
|
||||
struct http_connect_state *state = tevent_req_data(
|
||||
req, struct http_connect_state);
|
||||
struct tevent_req *subreq = NULL;
|
||||
int ret;
|
||||
|
||||
ret = tsocket_address_inet_from_strings(state,
|
||||
"ip",
|
||||
state->http_server_ip,
|
||||
state->http_port,
|
||||
&state->remote_address);
|
||||
if (ret != 0) {
|
||||
int saved_errno = errno;
|
||||
|
||||
DBG_ERR("Cannot create remote socket address, error: %s (%d)\n",
|
||||
strerror(errno), errno);
|
||||
tevent_req_error(req, saved_errno);
|
||||
return;
|
||||
}
|
||||
|
||||
subreq = tstream_inet_tcp_connect_send(state,
|
||||
state->ev,
|
||||
state->local_address,
|
||||
state->remote_address);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
tevent_req_set_callback(subreq, http_connect_tcp_done, req);
|
||||
}
|
||||
|
||||
static void http_connect_tcp_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct http_connect_state *state = tevent_req_data(
|
||||
req, struct http_connect_state);
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
ret = tstream_inet_tcp_connect_recv(subreq,
|
||||
&error,
|
||||
state->http_conn,
|
||||
&state->http_conn->tstreams.raw,
|
||||
NULL);
|
||||
TALLOC_FREE(subreq);
|
||||
if (ret != 0) {
|
||||
tevent_req_error(req, error);
|
||||
return;
|
||||
}
|
||||
|
||||
state->http_conn->tstreams.active = state->http_conn->tstreams.raw;
|
||||
DBG_DEBUG("Socket connected\n");
|
||||
|
||||
if (state->tls_params == NULL) {
|
||||
tevent_req_done(req);
|
||||
return;
|
||||
}
|
||||
|
||||
DBG_DEBUG("Starting TLS\n");
|
||||
|
||||
subreq = tstream_tls_connect_send(state,
|
||||
state->ev,
|
||||
state->http_conn->tstreams.active,
|
||||
state->tls_params);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return;
|
||||
}
|
||||
tevent_req_set_callback(subreq, http_connect_tls_done, req);
|
||||
}
|
||||
|
||||
static void http_connect_tls_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
struct http_connect_state *state = tevent_req_data(
|
||||
req, struct http_connect_state);
|
||||
int error;
|
||||
int ret;
|
||||
|
||||
ret = tstream_tls_connect_recv(subreq,
|
||||
&error,
|
||||
state->http_conn,
|
||||
&state->http_conn->tstreams.tls);
|
||||
TALLOC_FREE(subreq);
|
||||
if (ret != 0) {
|
||||
tevent_req_error(req, error);
|
||||
return;
|
||||
}
|
||||
|
||||
state->http_conn->tstreams.active = state->http_conn->tstreams.tls;
|
||||
|
||||
DBG_DEBUG("TLS handshake completed\n");
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
int http_connect_recv(struct tevent_req *req,
|
||||
TALLOC_CTX *mem_ctx,
|
||||
struct http_conn **http_conn)
|
||||
{
|
||||
struct http_connect_state *state = tevent_req_data(
|
||||
req, struct http_connect_state);
|
||||
int error;
|
||||
|
||||
if (tevent_req_is_unix_error(req, &error)) {
|
||||
tevent_req_received(req);
|
||||
return error;
|
||||
}
|
||||
|
||||
*http_conn = talloc_move(mem_ctx, &state->http_conn);
|
||||
tevent_req_received(req);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct tevent_queue *http_conn_send_queue(struct http_conn *http_conn)
|
||||
{
|
||||
return http_conn->send_queue;
|
||||
}
|
||||
|
||||
struct tstream_context *http_conn_tstream(struct http_conn *http_conn)
|
||||
{
|
||||
return http_conn->tstreams.active;
|
||||
}
|
||||
|
||||
struct http_conn_disconnect_state {
|
||||
struct tevent_context *ev;
|
||||
struct http_conn *http_conn;
|
||||
};
|
||||
|
||||
static void http_conn_disconnect_done(struct tevent_req *subreq);
|
||||
|
||||
struct tevent_req *http_disconnect_send(TALLOC_CTX *mem_ctx,
|
||||
struct tevent_context *ev,
|
||||
struct http_conn *http_conn)
|
||||
{
|
||||
struct tevent_req *req = NULL;
|
||||
struct tevent_req *subreq = NULL;
|
||||
struct http_conn_disconnect_state *state = NULL;
|
||||
|
||||
req = tevent_req_create(mem_ctx, &state,
|
||||
struct http_conn_disconnect_state);
|
||||
if (req == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*state = (struct http_conn_disconnect_state) {
|
||||
.ev = ev,
|
||||
.http_conn = http_conn,
|
||||
};
|
||||
|
||||
if (http_conn->tstreams.active == NULL) {
|
||||
tevent_req_error(req, ENOTCONN);
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
|
||||
subreq = tstream_disconnect_send(state, ev, http_conn->tstreams.active);
|
||||
if (tevent_req_nomem(subreq, req)) {
|
||||
return tevent_req_post(req, ev);
|
||||
}
|
||||
tevent_req_set_callback(subreq, http_conn_disconnect_done, req);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
||||
static void http_conn_disconnect_done(struct tevent_req *subreq)
|
||||
{
|
||||
struct tevent_req *req = tevent_req_callback_data(
|
||||
subreq, struct tevent_req);
|
||||
int ret;
|
||||
int error;
|
||||
|
||||
ret = tstream_disconnect_recv(subreq, &error);
|
||||
TALLOC_FREE(subreq);
|
||||
if (ret == -1) {
|
||||
tevent_req_error(req, error);
|
||||
return;
|
||||
}
|
||||
|
||||
tevent_req_done(req);
|
||||
}
|
||||
|
||||
int http_disconnect_recv(struct tevent_req *req)
|
||||
{
|
||||
return tevent_req_simple_recv_unix(req);
|
||||
}
|
@ -38,6 +38,15 @@ enum http_read_status {
|
||||
HTTP_DATA_TOO_LONG,
|
||||
};
|
||||
|
||||
struct http_conn {
|
||||
struct tevent_queue *send_queue;
|
||||
struct {
|
||||
struct tstream_context *raw;
|
||||
struct tstream_context *tls;
|
||||
struct tstream_context *active;
|
||||
} tstreams;
|
||||
};
|
||||
|
||||
struct http_send_request_state {
|
||||
struct tevent_context *ev;
|
||||
struct tstream_context *stream;
|
||||
|
@ -1,8 +1,8 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
bld.SAMBA_LIBRARY('http',
|
||||
source='http.c http_auth.c',
|
||||
deps='talloc tevent samba3core',
|
||||
source='http.c http_auth.c http_conn.c',
|
||||
deps='talloc tevent samba3core dns_lookup',
|
||||
private_library=True,
|
||||
)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user