int expect_asn1; /* Response must be ASN.1-encoded */
unsigned char *pos; /* Current position sending data */
long len_to_send; /* Number of bytes still to send */
- unsigned long resp_len; /* Length of response */
- size_t max_resp_len; /* Maximum length of response */
+ size_t resp_len; /* Length of response */
+ size_t max_resp_len; /* Maximum length of response, or 0 */
int keep_alive; /* Persistent conn. 0=no, 1=prefer, 2=require */
time_t max_time; /* Maximum end time of current transfer, or 0 */
time_t max_total_time; /* Maximum end time of total transfer, or 0 */
/* HTTP states */
-#define OHS_NOREAD 0x1000 /* If set no reading should be performed */
-#define OHS_ERROR (0 | OHS_NOREAD) /* Error condition */
-#define OHS_FIRSTLINE 1 /* First line of response being read */
-#define OHS_HEADERS 2 /* MIME headers of response being read */
-#define OHS_REDIRECT 3 /* MIME headers being read, expecting Location */
-#define OHS_ASN1_HEADER 4 /* HTTP initial header (tag+length) being read */
-#define OHS_CONTENT 5 /* HTTP content octets being read */
+#define OHS_NOREAD 0x1000 /* If set no reading should be performed */
+#define OHS_ERROR (0 | OHS_NOREAD) /* Error condition */
#define OHS_ADD_HEADERS (1 | OHS_NOREAD) /* Adding header lines to request */
#define OHS_WRITE_INIT (2 | OHS_NOREAD) /* 1st call: ready to start send */
#define OHS_WRITE_HDR (3 | OHS_NOREAD) /* Request header being sent */
#define OHS_WRITE_REQ (4 | OHS_NOREAD) /* Request contents being sent */
#define OHS_FLUSH (5 | OHS_NOREAD) /* Request being flushed */
-#define OHS_DONE (6 | OHS_NOREAD) /* Completed */
+#define OHS_FIRSTLINE 1 /* First line of response being read */
+#define OHS_HEADERS 2 /* MIME headers of response being read */
+#define OHS_REDIRECT 3 /* MIME headers being read, expecting Location */
+#define OHS_ASN1_HEADER 4 /* ASN1 sequence header (tag+length) being read */
+#define OHS_ASN1_CONTENT 5 /* ASN1 content octets being read */
+#define OHS_ASN1_DONE (6 | OHS_NOREAD) /* ASN1 content read completed */
+#define OHS_STREAM (7 | OHS_NOREAD) /* HTTP content stream to be read */
/* Low-level HTTP API implementation */
void *arg, int use_ssl,
const char *proxy,
const char *server, const char *port,
- int buf_size, unsigned long max_len,
- int overall_timeout)
+ int buf_size, int overall_timeout)
{
OSSL_HTTP_REQ_CTX *rctx = OSSL_HTTP_REQ_CTX_new(wbio, rbio, buf_size);
if (rctx == NULL)
return NULL;
- OSSL_HTTP_REQ_CTX_set_max_response_length(rctx, max_len);
rctx->free_wbio = free_wbio;
rctx->upd_fn = bio_update_fn;
rctx->upd_arg = arg;
static int parse_http_line1(char *line, int *found_keep_alive)
{
- int retcode;
+ int i, retcode;
char *code, *reason, *end;
if (strncmp(line, HTTP_PREFIX_VERSION, HTTP_VERSION_PATT_LEN) != 0)
}
err:
- ERR_raise_data(ERR_LIB_HTTP, HTTP_R_HEADER_PARSE_ERROR, "%.40s", line);
+ i = 0;
+ while (i < 60 && ossl_isprint(line[i]))
+ i++;
+ line[i] = '\0';
+ ERR_raise_data(ERR_LIB_HTTP, HTTP_R_HEADER_PARSE_ERROR, "content=%s", line);
return 0;
}
-static int check_set_resp_len(OSSL_HTTP_REQ_CTX *rctx, unsigned long len)
+static int check_set_resp_len(OSSL_HTTP_REQ_CTX *rctx, size_t len)
{
- if (len > rctx->max_resp_len)
+ if (rctx->max_resp_len != 0 && len > rctx->max_resp_len)
ERR_raise_data(ERR_LIB_HTTP, HTTP_R_MAX_RESP_LEN_EXCEEDED,
- "length=%lu, max=%lu", len, rctx->max_resp_len);
+ "length=%zu, max=%zu", len, rctx->max_resp_len);
if (rctx->resp_len != 0 && rctx->resp_len != len)
ERR_raise_data(ERR_LIB_HTTP, HTTP_R_INCONSISTENT_CONTENT_LENGTH,
- "ASN.1 length=%lu, Content-Length=%lu",
+ "ASN.1 length=%zu, Content-Length=%zu",
len, rctx->resp_len);
rctx->resp_len = len;
return 1;
{
int i, found_expected_ct = 0, found_keep_alive = 0;
long n;
- unsigned long resp_len;
+ size_t resp_len;
const unsigned char *p;
char *key, *value, *line_end = NULL;
rctx->redirection_url = NULL;
next_io:
if ((rctx->state & OHS_NOREAD) == 0) {
- n = BIO_read(rctx->rbio, rctx->readbuf, rctx->readbuflen);
+ if (rctx->expect_asn1)
+ n = BIO_read(rctx->rbio, rctx->readbuf, rctx->readbuflen);
+ else
+ n = BIO_gets(rctx->rbio, (char *)rctx->readbuf, rctx->readbuflen);
if (n <= 0) {
if (BIO_should_retry(rctx->rbio))
return -1;
found_keep_alive = 0;
}
if (strcasecmp(key, "Content-Length") == 0) {
- resp_len = strtoul(value, &line_end, 10);
+ resp_len = (size_t)strtoul(value, &line_end, 10);
if (line_end == value || *line_end != '\0') {
ERR_raise_data(ERR_LIB_HTTP,
HTTP_R_ERROR_PARSING_CONTENT_LENGTH,
}
if (!rctx->expect_asn1) {
- rctx->state = OHS_CONTENT;
- goto content;
+ rctx->state = OHS_STREAM;
+ return 1;
}
rctx->state = OHS_ASN1_HEADER;
if (!check_set_resp_len(rctx, resp_len))
return 0;
- content:
- rctx->state = OHS_CONTENT;
+ rctx->state = OHS_ASN1_CONTENT;
/* Fall thru */
- case OHS_CONTENT:
+ case OHS_ASN1_CONTENT:
default:
n = BIO_get_mem_data(rctx->mem, NULL);
- if (n < (long)rctx->resp_len /* may be 0 if no Content-Length or ASN.1 */)
+ if (n < 0 || (size_t)n < rctx->resp_len)
goto next_io;
- rctx->state = OHS_DONE;
+ rctx->state = OHS_ASN1_DONE;
return 1;
}
}
}
return NULL;
}
- return rctx->mem;
+ return rctx->state == OHS_STREAM ? rctx->rbio : rctx->mem;
}
int OSSL_HTTP_is_alive(const OSSL_HTTP_REQ_CTX *rctx)
const char *proxy, const char *no_proxy,
int use_ssl, BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
- int buf_size, unsigned long max_resp_len,
- int overall_timeout)
+ int buf_size, int overall_timeout)
{
BIO *cbio; /* == bio if supplied, used as connection BIO if rbio is NULL */
OSSL_HTTP_REQ_CTX *rctx = NULL;
rctx = http_req_ctx_new(bio == NULL, cbio, rbio != NULL ? rbio : cbio,
bio_update_fn, arg, use_ssl, proxy, server, port,
- buf_size, max_resp_len, overall_timeout);
+ buf_size, overall_timeout);
end:
if (rctx != NULL)
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
- int timeout, int keep_alive)
+ size_t max_resp_len, int timeout, int keep_alive)
{
int use_http_proxy;
ERR_raise(ERR_LIB_HTTP, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
+ rctx->max_resp_len = max_resp_len; /* allows for 0: indefinite */
return OSSL_HTTP_REQ_CTX_set_request_line(rctx, req != NULL,
use_http_proxy ? rctx->server
rctx = OSSL_HTTP_open(host, port, proxy, no_proxy,
use_ssl, bio, rbio, bio_update_fn, arg,
- buf_size, max_resp_len, timeout);
+ buf_size, timeout);
new_rpath:
if (rctx != NULL) {
if (!OSSL_HTTP_set_request(rctx, path, headers,
NULL /* content_type */,
NULL /* req */,
- expected_ct, expect_asn1,
+ expected_ct, expect_asn1, max_resp_len,
-1 /* use same max time (timeout) */,
0 /* no keep_alive */))
OSSL_HTTP_REQ_CTX_free(rctx);
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_ct, int expect_asn1,
- unsigned long max_resp_len, int timeout, int keep_alive)
+ size_t max_resp_len, int timeout, int keep_alive)
{
OSSL_HTTP_REQ_CTX *rctx = prctx == NULL ? NULL : *prctx;
BIO *resp = NULL;
if (rctx == NULL) {
rctx = OSSL_HTTP_open(server, port, proxy, no_proxy,
use_ssl, bio, rbio, bio_update_fn, arg,
- buf_size, max_resp_len, timeout);
+ buf_size, timeout);
timeout = -1; /* Already set during opening the connection */
}
if (rctx != NULL) {
if (OSSL_HTTP_set_request(rctx, path, headers, content_type, req,
expected_ct, expect_asn1,
- timeout, keep_alive))
+ max_resp_len, timeout, keep_alive))
resp = OSSL_HTTP_exchange(rctx, NULL);
if (resp == NULL || !OSSL_HTTP_is_alive(rctx)) {
if (!OSSL_HTTP_close(rctx, resp != NULL)) {
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
- int timeout, int keep_alive);
+ size_t max_resp_len, int timeout, int keep_alive);
BIO *OSSL_HTTP_exchange(OSSL_HTTP_REQ_CTX *rctx, char **redirection_url);
BIO *OSSL_HTTP_get(const char *url, const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
A value <= 0 indicates that
the B<HTTP_DEFAULT_MAX_LINE_LENGTH> of 4KiB should be used.
This length is also used as the number of content bytes that are read at a time.
-The I<max_resp_len> specifies the maximum allowed response content length.
-The value 0 indicates B<HTTP_DEFAULT_MAX_RESP_LEN>, which currently is 100 KiB.
If the I<overall_timeout> parameter is > 0 this indicates the maximum number of
seconds the overall HTTP transfer (i.e., connection setup if needed,
is included in the HTTP header of the response and return an error if not.
If the I<expect_asn1> parameter is nonzero,
a structure in ASN.1 encoding will be expected as response content.
+The I<max_resp_len> parameter specifies the maximum allowed
+response content length, where the value 0 indicates no limit.
If the I<timeout> parameter is > 0 this indicates the maximum number of seconds
the subsequent HTTP transfer (sending the request and receiving a response)
is allowed to take.
return 1 on success, 0 on error.
On success, OSSL_HTTP_exchange(), OSSL_HTTP_get(), and OSSL_HTTP_transfer()
-return a memory BIO containing the data received.
-This must be freed by the caller.
+return a memory BIO containing the data received if an ASN.1-encoded response
+is expected, else a BIO that may support streaming.
+The BIO must be freed by the caller.
On failure, they return NULL.
Failure conditions include connection/transfer timeout, parse errors, etc.
const char *proxy, const char *no_proxy,
int use_ssl, BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
- int buf_size, unsigned long max_resp_len,
- int overall_timeout);
+ int buf_size, int overall_timeout);
int OSSL_HTTP_proxy_connect(BIO *bio, const char *server, const char *port,
const char *proxyuser, const char *proxypass,
int timeout, BIO *bio_err, const char *prog);
const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
- int timeout, int keep_alive);
+ size_t max_resp_len, int timeout, int keep_alive);
BIO *OSSL_HTTP_exchange(OSSL_HTTP_REQ_CTX *rctx, char **redirection_url);
BIO *OSSL_HTTP_get(const char *url, const char *proxy, const char *no_proxy,
BIO *bio, BIO *rbio,
OSSL_HTTP_bio_cb_t bio_update_fn, void *arg,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *expected_content_type, int expect_asn1,
- unsigned long max_resp_len, int timeout);
+ size_t max_resp_len, int timeout);
BIO *OSSL_HTTP_transfer(OSSL_HTTP_REQ_CTX **prctx,
const char *server, const char *port,
const char *path, int use_ssl,
int buf_size, const STACK_OF(CONF_VALUE) *headers,
const char *content_type, BIO *req,
const char *expected_content_type, int expect_asn1,
- unsigned long max_resp_len, int timeout, int keep_alive);
+ size_t max_resp_len, int timeout, int keep_alive);
int OSSL_HTTP_close(OSSL_HTTP_REQ_CTX *rctx, int ok);
/* Auxiliary functions */