http-client-request.c revision 35f3b7e05afecacd0332c210c6e253911c2813d8
/* Copyright (c) 2013 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "net.h"
#include "str.h"
#include "hash.h"
#include "array.h"
#include "istream.h"
#include "ostream.h"
#include "http-url.h"
#include "http-date.h"
#include "http-response-parser.h"
#include "http-transfer.h"
#include "http-client-private.h"
const char *http_request_state_names[] = {
"new",
"queued",
"payload_out",
"waiting",
"got_response",
"payload_in",
"finished",
"aborted"
};
/*
* Logging
*/
static inline void
static inline void
const char *format, ...)
{
i_debug("http-client: request %s: %s",
}
}
/*
* Request
*/
static struct http_client_request *
{
struct http_client_request *req;
return req;
}
struct http_client_request *
{
struct http_client_request *req;
return req;
}
struct http_client_request *
{
struct http_client_request *req;
return req;
}
struct http_client_request *
void *context)
{
struct http_client_request *req;
return req;
}
struct http_client_request *
void *context)
{
struct http_client_request *req;
return req;
}
{
}
{
return;
}
/* only decrease pending request counter if this request was submitted */
}
{
}
bool ssl)
{
}
{
}
{
/* mark presence of special headers */
switch (key[0]) {
case 'c': case 'C':
break;
case 'd': case 'D':
break;
case 'e': case 'E':
break;
case 'h': case 'H':
break;
case 't': case 'T':
break;
case 'u': case 'U':
break;
}
}
{
}
{
int ret;
if (ret < 0) {
i_error("i_stream_get_size(%s) failed: %s",
}
req->payload_size = 0;
}
/* prepare request payload sync using 100 Continue response from server */
}
enum http_request_state
{
}
{
Section 3.3:
The presence of a message body in a response depends on both the
request method to which it is responding and the response status code.
Responses to the HEAD request method never include a message body
because the associated response header fields, if present, indicate only
what their values would have been if the request method had been GET
2xx (Successful) responses to CONNECT switch to tunnel mode instead of
having a message body (Section 4.3.6 of [Part2]).
*/
}
{
struct http_client_host *host;
if (req->connect_tunnel) {
/* connect requests require authority form for request target */
} else {
/* absolute target url */
}
/* determine what host to contact to submit this request */
!req->connect_tunnel) {
} else {
}
} else {
}
/* use submission date if no date is set explicitly */
/* prepare value for Host header */
/* debug label */
/* update request target */
/* if we don't have a proxy, CONNECT requests are handled by creating
the requested connection directly */
if (req->connect_direct)
}
}
{
}
static void
{
}
}
static int
{
int ret;
} else {
}
req->payload_size = 0;
/* Wait for payload data to be written */
break;
}
}
ret = 1;
else
/* Return status */
return ret;
}
{
}
{
}
{
(void)http_client_connection_output(conn);
}
const char **error_r)
{
int fd;
/* chunked ostream needs to write to the parent stream's buffer */
/* the payload stream assigned to this request is broken,
fail this the request immediately */
"Broken payload stream");
/* we're in the middle of sending a request, so the connection
will also have to be aborted */
ret = -1;
} else if (output->stream_errno != 0) {
/* failed to send request */
ret = -1;
} else {
}
if (!req->payload_chunked &&
*error_r = "stream input size changed [BUG]";
return -1;
}
if (req->payload_wait) {
} else {
}
/* output is blocking */
} else {
/* input is blocking */
}
return ret < 0 ? -1 : 0;
}
const char **error_r)
{
int ret = 0;
/* create request line */
/* create special headers implicitly if not set explicitly using
http_client_request_add_header() */
if (!req->have_hdr_host) {
}
if (!req->have_hdr_date) {
}
}
}
if (req->payload_chunked) {
// FIXME: can't do this for a HTTP/1.0 server
if (!req->have_hdr_body_spec)
/* send Content-Length if we have specified a payload,
even if it's 0 bytes. */
if (!req->have_hdr_body_spec) {
req->payload_size);
}
}
Section 19.7.1:
A client MUST NOT send the Keep-Alive connection token to a proxy
server as HTTP/1.0 proxy servers do not obey the rules of HTTP/1.1
for parsing the Connection header field.
*/
}
/* request line + implicit headers */
/* explicit headers */
} else {
}
/* end of header */
ret = -1;
}
if (!req->payload_sync) {
ret = -1;
} else {
}
} else {
}
return ret;
}
const char **error_r)
{
int ret;
T_BEGIN {
} T_END;
return ret;
}
struct http_response *response)
{
/* retrying */
return FALSE;
} else {
}
}
return TRUE;
}
void
{
return;
struct http_response response;
}
}
{
struct http_client_request *const *reqs;
unsigned int i, count;
req->delayed_error);
for (i = 0; i < count; i++) {
return;
}
}
i_unreached();
}
{
}
{
/* we're still in http_client_request_submit(). delay
reporting the error, so the caller doesn't have to handle
immediate callbacks. */
} else {
}
}
{
return;
}
{
return;
}
{
/* parse URL */
return;
}
t_strdup_printf("Redirected more than %d times",
} else {
"Redirect refused");
}
return;
}
/* rewind payload stream */
"Redirect failed: Cannot resend payload; stream is not seekable");
return;
} else {
}
}
/* drop payload output stream from previous attempt */
}
origin_url, target);
Section-7.4.4
-> A 303 `See Other' redirect status response is handled a bit differently.
Basically, the response content is located elsewhere, but the original
(POST) request is handled already.
*/
// FIXME: should we provide the means to skip this step? The original
// request was already handled at this point.
/* drop payload */
req->payload_size = 0;
req->payload_offset = 0;
}
/* resubmit */
}
{
/* rewind payload stream */
"Resubmission failed: Cannot resend payload; stream is not seekable");
return;
} else {
}
}
/* rewind payload stream */
"Resubmission failed: Cannot resend payload; stream is not seekable");
return;
} else {
}
}
/* drop payload output stream from previous attempt */
}
{
if (!http_client_request_try_retry(req))
}
struct http_response *response)
{
if (!http_client_request_try_retry(req)) {
}
}
{
/* limit the number of attempts for each request */
return FALSE;
return TRUE;
}
void (*callback)(void *),
void *context)
{
}
struct http_client_tunnel *tunnel)
{
}