mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-10 09:58:01 +00:00
Merge HTTP proxy fixes from 'pre-0.77'.
This commit is contained in:
commit
5886d610d8
92
proxy/http.c
92
proxy/http.c
@ -72,7 +72,8 @@ typedef struct HttpProxyNegotiator {
|
|||||||
uint32_t nonce_count;
|
uint32_t nonce_count;
|
||||||
prompts_t *prompts;
|
prompts_t *prompts;
|
||||||
int username_prompt_index, password_prompt_index;
|
int username_prompt_index, password_prompt_index;
|
||||||
size_t content_length;
|
size_t content_length, chunk_length;
|
||||||
|
bool chunked_transfer;
|
||||||
ProxyNegotiator pn;
|
ProxyNegotiator pn;
|
||||||
} HttpProxyNegotiator;
|
} HttpProxyNegotiator;
|
||||||
|
|
||||||
@ -151,7 +152,9 @@ static void proxy_http_free(ProxyNegotiator *pn)
|
|||||||
#define HTTP_HEADER_LIST(X) \
|
#define HTTP_HEADER_LIST(X) \
|
||||||
X(HDR_CONNECTION, "Connection") \
|
X(HDR_CONNECTION, "Connection") \
|
||||||
X(HDR_CONTENT_LENGTH, "Content-Length") \
|
X(HDR_CONTENT_LENGTH, "Content-Length") \
|
||||||
|
X(HDR_TRANSFER_ENCODING, "Transfer-Encoding") \
|
||||||
X(HDR_PROXY_AUTHENTICATE, "Proxy-Authenticate") \
|
X(HDR_PROXY_AUTHENTICATE, "Proxy-Authenticate") \
|
||||||
|
X(HDR_PROXY_CONNECTION, "Proxy-Connection") \
|
||||||
/* end of list */
|
/* end of list */
|
||||||
|
|
||||||
typedef enum HttpHeader {
|
typedef enum HttpHeader {
|
||||||
@ -322,7 +325,7 @@ static HttpAuthDetails *parse_http_auth_header(HttpProxyNegotiator *s)
|
|||||||
d->hash_username = !stricmp(s->token->s, "true");
|
d->hash_username = !stricmp(s->token->s, "true");
|
||||||
} else if (!stricmp(s->token->s, "algorithm")) {
|
} else if (!stricmp(s->token->s, "algorithm")) {
|
||||||
if (!get_separator(s, '=') ||
|
if (!get_separator(s, '=') ||
|
||||||
!get_token(s))
|
(!get_token(s) && !get_quoted_string(s)))
|
||||||
return auth_error(d, "parse error in Digest algorithm "
|
return auth_error(d, "parse error in Digest algorithm "
|
||||||
"field");
|
"field");
|
||||||
bool found = false;
|
bool found = false;
|
||||||
@ -460,6 +463,7 @@ static void proxy_http_process_queue(ProxyNegotiator *pn)
|
|||||||
crReturnV;
|
crReturnV;
|
||||||
|
|
||||||
s->content_length = 0;
|
s->content_length = 0;
|
||||||
|
s->chunked_transfer = false;
|
||||||
s->connection_close = false;
|
s->connection_close = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -530,7 +534,25 @@ static void proxy_http_process_queue(ProxyNegotiator *pn)
|
|||||||
if (!get_token(s))
|
if (!get_token(s))
|
||||||
continue;
|
continue;
|
||||||
s->content_length = strtoumax(s->token->s, NULL, 10);
|
s->content_length = strtoumax(s->token->s, NULL, 10);
|
||||||
} else if (hdr == HDR_CONNECTION) {
|
} else if (hdr == HDR_TRANSFER_ENCODING) {
|
||||||
|
/*
|
||||||
|
* The Transfer-Encoding header value should be a
|
||||||
|
* comma-separated list of keywords including
|
||||||
|
* "chunked", "deflate" and "gzip". We parse it in the
|
||||||
|
* most superficial way, by just looking for "chunked"
|
||||||
|
* and ignoring everything else.
|
||||||
|
*
|
||||||
|
* It's OK to do that because we're not actually
|
||||||
|
* _using_ the error document - we only have to skip
|
||||||
|
* over it to find the end of the HTTP response. So we
|
||||||
|
* don't care if it's gzipped or not.
|
||||||
|
*/
|
||||||
|
while (get_token(s)) {
|
||||||
|
if (!stricmp(s->token->s, "chunked"))
|
||||||
|
s->chunked_transfer = true;
|
||||||
|
}
|
||||||
|
} else if (hdr == HDR_CONNECTION ||
|
||||||
|
hdr == HDR_PROXY_CONNECTION) {
|
||||||
if (!get_token(s))
|
if (!get_token(s))
|
||||||
continue;
|
continue;
|
||||||
if (!stricmp(s->token->s, "close"))
|
if (!stricmp(s->token->s, "close"))
|
||||||
@ -584,8 +606,62 @@ static void proxy_http_process_queue(ProxyNegotiator *pn)
|
|||||||
} while (s->header->len > 0);
|
} while (s->header->len > 0);
|
||||||
|
|
||||||
/* Read and ignore the entire response document */
|
/* Read and ignore the entire response document */
|
||||||
crMaybeWaitUntilV(bufchain_try_consume(
|
if (!s->chunked_transfer) {
|
||||||
pn->input, s->content_length));
|
/* Simple approach: read exactly Content-Length bytes */
|
||||||
|
crMaybeWaitUntilV(bufchain_try_consume(
|
||||||
|
pn->input, s->content_length));
|
||||||
|
} else {
|
||||||
|
/* Chunked transfer: read a sequence of
|
||||||
|
* <hex length>\r\n<data>\r\n chunks, terminating in one with
|
||||||
|
* zero length */
|
||||||
|
do {
|
||||||
|
/*
|
||||||
|
* Expect a chunk length
|
||||||
|
*/
|
||||||
|
s->chunk_length = 0;
|
||||||
|
while (true) {
|
||||||
|
char c;
|
||||||
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
|
pn->input, &c, 1));
|
||||||
|
if (c == '\r') {
|
||||||
|
continue;
|
||||||
|
} else if (c == '\n') {
|
||||||
|
break;
|
||||||
|
} else if ('0' <= c && c <= '9') {
|
||||||
|
s->chunk_length = s->chunk_length*16 + (c-'0');
|
||||||
|
} else if ('A' <= c && c <= 'F') {
|
||||||
|
s->chunk_length = s->chunk_length*16 + (c-'A'+10);
|
||||||
|
} else if ('a' <= c && c <= 'f') {
|
||||||
|
s->chunk_length = s->chunk_length*16 + (c-'a'+10);
|
||||||
|
} else {
|
||||||
|
pn->error = dupprintf(
|
||||||
|
"Received bad character 0x%02X in chunk length "
|
||||||
|
"during HTTP chunked transfer encoding",
|
||||||
|
(unsigned)(unsigned char)c);
|
||||||
|
crStopV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Expect that many bytes of chunked data
|
||||||
|
*/
|
||||||
|
crMaybeWaitUntilV(bufchain_try_consume(
|
||||||
|
pn->input, s->chunk_length));
|
||||||
|
|
||||||
|
/* Now expect \r\n */
|
||||||
|
{
|
||||||
|
char buf[2];
|
||||||
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
||||||
|
pn->input, buf, 2));
|
||||||
|
if (memcmp(buf, "\r\n", 2)) {
|
||||||
|
pn->error = dupprintf(
|
||||||
|
"Missing CRLF after chunk "
|
||||||
|
"during HTTP chunked transfer encoding");
|
||||||
|
crStopV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (s->chunk_length);
|
||||||
|
}
|
||||||
|
|
||||||
if (200 <= s->http_status && s->http_status < 300) {
|
if (200 <= s->http_status && s->http_status < 300) {
|
||||||
/* Any 2xx HTTP response means we're done */
|
/* Any 2xx HTTP response means we're done */
|
||||||
@ -594,9 +670,9 @@ static void proxy_http_process_queue(ProxyNegotiator *pn)
|
|||||||
/* 407 is Proxy Authentication Required, which we may be
|
/* 407 is Proxy Authentication Required, which we may be
|
||||||
* able to do something about. */
|
* able to do something about. */
|
||||||
if (s->connection_close) {
|
if (s->connection_close) {
|
||||||
pn->error = dupprintf("HTTP proxy closed connection after "
|
/* If we got 407 + connection closed, reconnect before
|
||||||
"asking for authentication");
|
* sending our next request. */
|
||||||
crStopV;
|
pn->reconnect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the best we can do is report some kind of error from
|
/* If the best we can do is report some kind of error from
|
||||||
|
@ -99,6 +99,7 @@ static void sk_proxy_close (Socket *s)
|
|||||||
ProxySocket *ps = container_of(s, ProxySocket, sock);
|
ProxySocket *ps = container_of(s, ProxySocket, sock);
|
||||||
|
|
||||||
sk_close(ps->sub_socket);
|
sk_close(ps->sub_socket);
|
||||||
|
sk_addr_free(ps->proxy_addr);
|
||||||
sk_addr_free(ps->remote_addr);
|
sk_addr_free(ps->remote_addr);
|
||||||
proxy_negotiator_cleanup(ps);
|
proxy_negotiator_cleanup(ps);
|
||||||
bufchain_clear(&ps->output_from_negotiator);
|
bufchain_clear(&ps->output_from_negotiator);
|
||||||
@ -223,6 +224,16 @@ static void proxy_negotiate(ProxySocket *ps)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ps->pn->reconnect) {
|
||||||
|
sk_close(ps->sub_socket);
|
||||||
|
SockAddr *proxy_addr = sk_addr_dup(ps->proxy_addr);
|
||||||
|
ps->sub_socket = sk_new(proxy_addr, ps->proxy_port,
|
||||||
|
ps->proxy_privport, ps->proxy_oobinline,
|
||||||
|
ps->proxy_nodelay, ps->proxy_keepalive,
|
||||||
|
&ps->plugimpl);
|
||||||
|
ps->pn->reconnect = false;
|
||||||
|
}
|
||||||
|
|
||||||
while (bufchain_size(&ps->output_from_negotiator)) {
|
while (bufchain_size(&ps->output_from_negotiator)) {
|
||||||
ptrlen data = bufchain_prefix(&ps->output_from_negotiator);
|
ptrlen data = bufchain_prefix(&ps->output_from_negotiator);
|
||||||
sk_write(ps->sub_socket, data.ptr, data.len);
|
sk_write(ps->sub_socket, data.ptr, data.len);
|
||||||
@ -601,10 +612,16 @@ Socket *new_connection(SockAddr *addr, const char *hostname,
|
|||||||
/* create the actual socket we will be using,
|
/* create the actual socket we will be using,
|
||||||
* connected to our proxy server and port.
|
* connected to our proxy server and port.
|
||||||
*/
|
*/
|
||||||
ps->sub_socket = sk_new(proxy_addr,
|
ps->proxy_addr = sk_addr_dup(proxy_addr);
|
||||||
conf_get_int(conf, CONF_proxy_port),
|
ps->proxy_port = conf_get_int(conf, CONF_proxy_port);
|
||||||
privport, oobinline,
|
ps->proxy_privport = privport;
|
||||||
nodelay, keepalive, &ps->plugimpl);
|
ps->proxy_oobinline = oobinline;
|
||||||
|
ps->proxy_nodelay = nodelay;
|
||||||
|
ps->proxy_keepalive = keepalive;
|
||||||
|
ps->sub_socket = sk_new(proxy_addr, ps->proxy_port,
|
||||||
|
ps->proxy_privport, ps->proxy_oobinline,
|
||||||
|
ps->proxy_nodelay, ps->proxy_keepalive,
|
||||||
|
&ps->plugimpl);
|
||||||
if (sk_socket_error(ps->sub_socket) != NULL)
|
if (sk_socket_error(ps->sub_socket) != NULL)
|
||||||
return &ps->sock;
|
return &ps->sock;
|
||||||
|
|
||||||
|
@ -22,6 +22,11 @@ struct ProxySocket {
|
|||||||
SockAddr *remote_addr;
|
SockAddr *remote_addr;
|
||||||
int remote_port;
|
int remote_port;
|
||||||
|
|
||||||
|
/* Parameters needed to make further connections to the proxy */
|
||||||
|
SockAddr *proxy_addr;
|
||||||
|
int proxy_port;
|
||||||
|
bool proxy_privport, proxy_oobinline, proxy_nodelay, proxy_keepalive;
|
||||||
|
|
||||||
bufchain pending_output_data;
|
bufchain pending_output_data;
|
||||||
bufchain pending_oob_output_data;
|
bufchain pending_oob_output_data;
|
||||||
bufchain pending_input_data;
|
bufchain pending_input_data;
|
||||||
@ -68,6 +73,11 @@ struct ProxyNegotiator {
|
|||||||
|
|
||||||
/* Set to report user abort during proxy negotiation. */
|
/* Set to report user abort during proxy negotiation. */
|
||||||
bool aborted;
|
bool aborted;
|
||||||
|
|
||||||
|
/* Set to request the centralised code to make a fresh connection
|
||||||
|
* to the proxy server, e.g. because an HTTP proxy slammed the
|
||||||
|
* connection shut after sending 407 Proxy Auth Required. */
|
||||||
|
bool reconnect;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ProxyNegotiatorVT {
|
struct ProxyNegotiatorVT {
|
||||||
|
Loading…
Reference in New Issue
Block a user