http2: fixed the header accessor functions for the push callback

This commit is contained in:
Daniel Stenberg 2015-06-01 15:52:46 +02:00
parent feea9263e9
commit f65ab8864e
5 changed files with 82 additions and 43 deletions

View File

@ -27,15 +27,8 @@ CURLMOPT_PUSHFUNCTION \- approve or deny server pushes
.nf
#include <curl/curl.h>
struct curl_headerpair {
unsigned char *name; /* zero terminated name */
size_t namelen; /* length of 'name' */
unsigned char *value; /* zero terminated name */
size_t valuelen; /* length of 'value' */
};
struct curl_headerpair *curl_pushheader_bynum(push_headers, int num);
struct curl_headerpair *curl_pushheader_byname(push_headers, char *name);
char *curl_pushheader_bynum(push_headers, int num);
char *curl_pushheader_byname(push_headers, char *name);
int curl_push_callback(CURL *parent,
CURL *easy,
@ -78,12 +71,12 @@ functions. These functions can only be used from within this callback and they
can only access the PUSH_PROMISE headers. The normal response headers will be
pased to the header callback for pushed streams just as for normal streams.
.IP curl_pushheader_bynum
Returns the header pair at index 'num' (or NULL). The returned pointer points
to a struct that will be freed when this callback returns.
Returns the header at index 'num' (or NULL). The returned pointer points
to a "name:value" string that will be freed when this callback returns.
.IP curl_pushheader_byname
Returns the header pair for the given header name (or NULL). This is a
shortcut so that the application doesn't have to loop through all headers to
find the one it is interested in.
Returns the value for the given header name (or NULL). This is a shortcut so
that the application doesn't have to loop through all headers to find the one
it is interested in.
.SH CALLBACK RETURN VALUE
.IP "CURL_PUSH_OK (0)"
The application has accepted the stream and it can now start receiving data,

View File

@ -294,18 +294,13 @@ typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
#define CURL_PUSH_OK 0
#define CURL_PUSH_DENY 1
struct curl_headerpair {
unsigned char *name; /* zero terminated name */
size_t namelen; /* length of 'name' */
unsigned char *value; /* zero terminated name */
size_t valuelen; /* length of 'value' */
};
struct curl_pushheaders; /* forward declaration only */
struct curl_headerpair *curl_pushheader_bynum(struct curl_pushheaders *h,
int num);
struct curl_headerpair *curl_pushheader_byname(struct curl_pushheaders *h,
char *name);
CURL_EXTERN char *curl_pushheader_bynum(struct curl_pushheaders *h,
size_t num);
CURL_EXTERN char *curl_pushheader_byname(struct curl_pushheaders *h,
char *name);
typedef int (*curl_push_callback)(CURL *parent,
CURL *easy,

View File

@ -176,6 +176,8 @@ static CURLcode http_disconnect(struct connectdata *conn, bool dead_connection)
if(http) {
Curl_add_buffer_free(http->header_recvbuf);
http->header_recvbuf = NULL; /* clear the pointer */
free(http->push_headers);
http->push_headers = NULL;
}
#else
(void)conn;
@ -1492,6 +1494,8 @@ CURLcode Curl_http_done(struct connectdata *conn,
DEBUGF(infof(data, "free header_recvbuf!!\n"));
Curl_add_buffer_free(http->header_recvbuf);
http->header_recvbuf = NULL; /* clear the pointer */
free(http->push_headers);
http->push_headers = NULL;
}
#endif

View File

@ -176,7 +176,10 @@ struct HTTP {
const uint8_t *upload_mem; /* points to a buffer to read from */
size_t upload_len; /* size of the buffer 'upload_mem' points to */
curl_off_t upload_left; /* number of bytes left to upload */
Curl_send_buffer *push_recvbuf; /* store incoming push headers */
char **push_headers; /* allocated array */
size_t push_headers_used; /* number of entries filled in */
size_t push_headers_alloc; /* number of entries allocated */
#endif
};

View File

@ -219,14 +219,42 @@ struct curl_pushheaders {
/*
* push header access function. Only to be used from within the push callback
*/
struct curl_headerpair *curl_pushheader_bynum(struct curl_pushheaders *h,
int num)
char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num)
{
/* Verify that we got a good easy handle in the push header struct, mostly to
detect rubbish input fast(er). */
if(!h || !GOOD_EASY_HANDLE(h->data))
return NULL;
(void)num;
else {
struct HTTP *stream = h->data->req.protop;
if(num < stream->push_headers_used)
return stream->push_headers[num];
}
return NULL;
}
/*
* push header access function. Only to be used from within the push callback
*/
char *curl_pushheader_byname(struct curl_pushheaders *h, char *header)
{
/* Verify that we got a good easy handle in the push header struct, mostly to
detect rubbish input fast(er). */
if(!h || !GOOD_EASY_HANDLE(h->data) || !header)
return NULL;
else {
struct HTTP *stream = h->data->req.protop;
size_t len = strlen(header);
size_t i;
for(i=0; i<stream->push_headers_used; i++) {
if(!strncmp(header, stream->push_headers[i], len)) {
/* sub-match, make sure that it us followed by a colon */
if(stream->push_headers[i][len] != ':')
continue;
return &stream->push_headers[i][len+1];
}
}
}
return NULL;
}
@ -283,13 +311,14 @@ static int push_promise(struct SessionHandle *data,
stream = data->req.protop;
#ifdef CURLDEBUG
fprintf(stderr, "PUSHHDR %s\n", stream->push_recvbuf->buffer);
#endif
rv = data->multi->push_cb(data, newhandle,
frame->nvlen, &heads,
stream->push_headers_used, &heads,
data->multi->push_userp);
/* free the headers array again */
free(stream->push_headers);
stream->push_headers = NULL;
if(rv) {
/* denied, kill off the new handle again */
(void)Curl_close(newhandle);
@ -667,15 +696,30 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* Store received PUSH_PROMISE headers to be used when the subsequent
PUSH_PROMISE callback comes */
if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
fprintf(stderr, "*** PUSH_PROMISE headers on stream %u for %u\n",
stream_id,
frame->push_promise.promised_stream_id);
if(!stream->push_recvbuf)
stream->push_recvbuf = Curl_add_buffer_init();
Curl_add_buffer(stream->push_recvbuf, name, namelen);
Curl_add_buffer(stream->push_recvbuf, ":", 1);
Curl_add_buffer(stream->push_recvbuf, value, valuelen);
Curl_add_buffer(stream->push_recvbuf, "\r\n", 2);
char *h;
if(!stream->push_headers) {
stream->push_headers_alloc = 10;
stream->push_headers = malloc(stream->push_headers_alloc *
sizeof(char *));
stream->push_headers_used = 0;
}
else if(stream->push_headers_used ==
stream->push_headers_alloc) {
char **headp;
stream->push_headers_alloc *= 2;
headp = realloc(stream->push_headers,
stream->push_headers_alloc * sizeof(char *));
if(!headp) {
free(stream->push_headers);
stream->push_headers = NULL;
return 1;
}
stream->push_headers = headp;
}
h = aprintf("%s:%s", name, value);
if(h)
stream->push_headers[stream->push_headers_used++] = h;
return 0;
}