Always accept SPDY/3 style name/value pairs from spdylay_submit_* and

translate them into SPDY/2 as needed.
This commit is contained in:
Tatsuhiro Tsujikawa 2012-03-06 23:43:45 +09:00
parent 7d9a7b3069
commit 00abfc8dd3
8 changed files with 187 additions and 44 deletions

View File

@ -563,24 +563,7 @@ void* spdylay_session_get_stream_user_data(spdylay_session *session,
* the lowest priority is 3. If the |session| is initialized with the
* version SPDYLAY_PROTO_SPDY3, the lowest priority is 7.
*
* If |session| is initialized with the version SPDYLAY_PROTO_SPDY2,
* |nv| must include following name/value pairs:
*
* "method"
* HTTP method (e.g., "GET", "POST", "HEAD", etc)
* "scheme"
* URI scheme (e.g., "https")
* "url"
* Absolute path and parameters of this request (e.g., "/foo",
* "/foo;bar;haz?h=j&y=123")
* "version"
* HTTP version (e.g., "HTTP/1.1")
*
* The "host" name/value pair (this is the same as the HTTP "Host"
* header field) is also required by some hosts.
*
* If |session| is initialized with the version SPDYLAY_PROTO_SPDY3,
* |nv| must include following name/value pairs:
* The |nv| must include following name/value pairs:
*
* ":method"
* HTTP method (e.g., "GET", "POST", "HEAD", etc)
@ -596,6 +579,10 @@ void* spdylay_session_get_stream_user_data(spdylay_session *session,
* "example.org:443"). This is the same as the HTTP "Host" header
* field.
*
* If the |session| is initialized with the version
* SPDYLAY_PROTO_SPDY2, the above names are translated to "method",
* "scheme", "url", "version" and "host" respectively.
*
* This function creates copies of all name/value pairs in |nv|. It
* also lower-cases all names in |nv|.
*
@ -637,22 +624,17 @@ int spdylay_submit_request(spdylay_session *session, uint8_t pri,
* Submits SYN_REPLY frame and optionally one or more DATA frames
* against stream |stream_id|.
*
* If |session| is initialized with the version SPDYLAY_PROTO_SPDY2,
* |nv| must include following name/value pairs:
*
* "status"
* HTTP status code (e.g., "200" or "200 OK")
* "version"
* HTTP response version (e.g., "HTTP/1.1")
*
* If |session| is initialized with the version SPDYLAY_PROTO_SPDY3,
* |nv| must include following name/value pairs:
* The |nv| must include following name/value pairs:
*
* ":status"
* HTTP status code (e.g., "200" or "200 OK")
* ":version"
* HTTP response version (e.g., "HTTP/1.1")
*
* If the |session| is initialized with the version
* SPDYLAY_PROTO_SPDY2, the above names are translated to "status" and
* "version" respectively.
*
* This function creates copies of all name/value pairs in |nv|. It
* also lower-cases all names in |nv|.
*

View File

@ -376,6 +376,43 @@ char** spdylay_frame_nv_norm_copy(const char **nv)
return nv_copy;
}
/* Table to translate SPDY/3 header names to SPDY/2. */
static char *spdylay_nv_3to2[] = {
":host", "host",
":method", "method",
":path", "url",
":scheme", "scheme",
":status", "status",
":version", "version",
NULL
};
void spdylay_frame_nv_3to2(char **nv)
{
int i, j;
for(i = 0; nv[i]; i += 2) {
for(j = 0; spdylay_nv_3to2[j]; j += 2) {
if(strcmp(nv[i], spdylay_nv_3to2[j]) == 0) {
nv[i] = spdylay_nv_3to2[j+1];
break;
}
}
}
}
void spdylay_frame_nv_2to3(char **nv)
{
int i, j;
for(i = 0; nv[i]; i += 2) {
for(j = 0; spdylay_nv_3to2[j]; j += 2) {
if(strcmp(nv[i], spdylay_nv_3to2[j+1]) == 0) {
nv[i] = spdylay_nv_3to2[j];
break;
}
}
}
}
void spdylay_frame_syn_stream_init(spdylay_syn_stream *frame,
uint16_t version, uint8_t flags,
int32_t stream_id, int32_t assoc_stream_id,

View File

@ -595,6 +595,16 @@ void spdylay_frame_nv_downcase(char **nv);
*/
char** spdylay_frame_nv_norm_copy(const char **nv);
/*
* Translates the |nv| in SPDY/3 header names into SPDY/2.
*/
void spdylay_frame_nv_3to2(char **nv);
/*
* Translates the |nv| in SPDY/2 header names into SPDY/3.
*/
void spdylay_frame_nv_2to3(char **nv);
/*
* Makes copy of |iv| and return the copy. The |niv| is the number of
* entries in |iv|. This function returns the pointer to the copy if

View File

@ -552,12 +552,18 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
stream_id = session->next_stream_id;
item->frame->syn_stream.stream_id = stream_id;
session->next_stream_id += 2;
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_3to2(item->frame->syn_stream.nv);
}
framebuflen = spdylay_frame_pack_syn_stream(&session->aob.framebuf,
&session->aob.framebufmax,
&session->nvbuf,
&session->nvbuflen,
&item->frame->syn_stream,
&session->hd_deflater);
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_2to3(item->frame->syn_stream.nv);
}
if(framebuflen < 0) {
return framebuflen;
}
@ -576,12 +582,18 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
item->frame->syn_reply.stream_id)) {
return SPDYLAY_ERR_INVALID_FRAME;
}
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_3to2(item->frame->syn_reply.nv);
}
framebuflen = spdylay_frame_pack_syn_reply(&session->aob.framebuf,
&session->aob.framebufmax,
&session->nvbuf,
&session->nvbuflen,
&item->frame->syn_reply,
&session->hd_deflater);
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_2to3(item->frame->syn_reply.nv);
}
if(framebuflen < 0) {
return framebuflen;
}
@ -620,12 +632,18 @@ static ssize_t spdylay_session_prep_frame(spdylay_session *session,
item->frame->headers.stream_id)) {
return SPDYLAY_ERR_INVALID_FRAME;
}
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_3to2(item->frame->headers.nv);
}
framebuflen = spdylay_frame_pack_headers(&session->aob.framebuf,
&session->aob.framebufmax,
&session->nvbuf,
&session->nvbuflen,
&item->frame->headers,
&session->hd_deflater);
if(session->version == SPDYLAY_PROTO_SPDY2) {
spdylay_frame_nv_2to3(item->frame->headers.nv);
}
if(framebuflen < 0) {
return framebuflen;
}

View File

@ -170,6 +170,8 @@ int main(int argc, char* argv[])
test_spdylay_frame_nv_downcase) ||
!CU_add_test(pSuite, "frame_pack_nv_duplicate_keys",
test_spdylay_frame_pack_nv_duplicate_keys) ||
!CU_add_test(pSuite, "frame_nv_2to3", test_spdylay_frame_nv_2to3) ||
!CU_add_test(pSuite, "frame_nv_3to2", test_spdylay_frame_nv_3to2) ||
!CU_add_test(pSuite, "stream_add_pushed_stream",
test_spdylay_stream_add_pushed_stream)) {
CU_cleanup_registry();

View File

@ -526,3 +526,53 @@ void test_spdylay_frame_nv_downcase()
CU_ASSERT(0 == strcmp("1000000007", nv[3]));
spdylay_frame_nv_del(nv);
}
void test_spdylay_frame_nv_2to3()
{
const char *nv_src[] = {
"host", "localhost",
"method", "GET",
"url", "/",
"accept", "*/*",
"scheme", "https",
"status", "200 OK",
"version", "HTTP/1.1",
NULL
};
char **nv;
nv = spdylay_frame_nv_copy(nv_src);
spdylay_frame_nv_2to3(nv);
CU_ASSERT(0 == strcmp(":host", nv[0]));
CU_ASSERT(0 == strcmp(":method", nv[2]));
CU_ASSERT(0 == strcmp(":path", nv[4]));
CU_ASSERT(0 == strcmp("accept", nv[6]));
CU_ASSERT(0 == strcmp(":scheme", nv[8]));
CU_ASSERT(0 == strcmp(":status", nv[10]));
CU_ASSERT(0 == strcmp(":version", nv[12]));
spdylay_frame_nv_del(nv);
}
void test_spdylay_frame_nv_3to2()
{
const char *nv_src[] = {
":host", "localhost",
":method", "GET",
":path", "/",
"accept", "*/*",
":scheme", "https",
":status", "200 OK",
":version", "HTTP/1.1",
NULL
};
char **nv;
nv = spdylay_frame_nv_copy(nv_src);
spdylay_frame_nv_3to2(nv);
CU_ASSERT(0 == strcmp("host", nv[0]));
CU_ASSERT(0 == strcmp("method", nv[2]));
CU_ASSERT(0 == strcmp("url", nv[4]));
CU_ASSERT(0 == strcmp("accept", nv[6]));
CU_ASSERT(0 == strcmp("scheme", nv[8]));
CU_ASSERT(0 == strcmp("status", nv[10]));
CU_ASSERT(0 == strcmp("version", nv[12]));
spdylay_frame_nv_del(nv);
}

View File

@ -43,5 +43,7 @@ void test_spdylay_frame_pack_window_update();
void test_spdylay_frame_pack_settings();
void test_spdylay_frame_nv_sort();
void test_spdylay_frame_nv_downcase();
void test_spdylay_frame_nv_2to3();
void test_spdylay_frame_nv_3to2();
#endif /* SPDYLAY_FRAME_TEST_H */

View File

@ -579,21 +579,36 @@ void test_spdylay_submit_response_with_null_data_read_callback()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { "Version", "HTTP/1.1", NULL };
accumulator acc;
const char *nv[] = { ":Version", "HTTP/1.1", NULL };
spdylay_data_provider data_prd = {{-1}, NULL};
spdylay_outbound_item *item;
my_user_data ud;
spdylay_frame frame;
acc.length = 0;
ud.acc = &acc;
memset(&callbacks, 0, sizeof(callbacks));
callbacks.send_callback = null_send_callback;
callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == spdylay_session_server_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
&callbacks, &ud));
spdylay_session_open_stream(session, 1, SPDYLAY_CTRL_FLAG_FIN, 3,
SPDYLAY_STREAM_OPENING, NULL);
CU_ASSERT(0 == spdylay_submit_response(session, 1, nv, &data_prd));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_reply.nv[0]));
CU_ASSERT(0 == strcmp(":version", item->frame->syn_reply.nv[0]));
CU_ASSERT(item->frame->syn_reply.hd.flags & SPDYLAY_CTRL_FLAG_FIN);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == spdylay_frame_unpack_syn_reply(&frame.syn_reply,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == strcmp("version", frame.syn_reply.nv[0]));
spdylay_session_del(session);
}
@ -627,23 +642,36 @@ void test_spdylay_submit_request_with_data()
void test_spdylay_submit_request_with_null_data_read_callback()
{
spdylay_session *session;
spdylay_session_callbacks callbacks = {
null_send_callback,
NULL,
NULL,
NULL
};
const char *nv[] = { "Version", "HTTP/1.1", NULL };
spdylay_session_callbacks callbacks;
accumulator acc;
const char *nv[] = { ":Version", "HTTP/1.1", NULL };
spdylay_data_provider data_prd = {{-1}, NULL};
spdylay_outbound_item *item;
my_user_data ud;
spdylay_frame frame;
acc.length = 0;
ud.acc = &acc;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = accumulator_send_callback;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, NULL));
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_request(session, 3, nv, &data_prd, NULL));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->syn_stream.nv[0]));
CU_ASSERT(0 == strcmp(":version", item->frame->syn_stream.nv[0]));
CU_ASSERT(item->frame->syn_stream.hd.flags & SPDYLAY_CTRL_FLAG_FIN);
CU_ASSERT(0 == spdylay_session_send(session));
CU_ASSERT(0 == spdylay_frame_unpack_syn_stream(&frame.syn_stream,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == strcmp("version", frame.syn_stream.nv[0]));
spdylay_session_del(session);
}
@ -724,20 +752,24 @@ void test_spdylay_submit_headers()
{
spdylay_session *session;
spdylay_session_callbacks callbacks;
const char *nv[] = { "version", "HTTP/1.1", NULL };
const char *nv[] = { ":Version", "HTTP/1.1", NULL };
my_user_data ud;
spdylay_outbound_item *item;
spdylay_stream *stream;
accumulator acc;
spdylay_frame frame;
acc.length = 0;
ud.acc = &acc;
memset(&callbacks, 0, sizeof(spdylay_session_callbacks));
callbacks.send_callback = null_send_callback;
callbacks.send_callback = accumulator_send_callback;
callbacks.on_ctrl_send_callback = on_ctrl_send_callback;
CU_ASSERT(0 == spdylay_session_client_new(&session, SPDYLAY_PROTO_SPDY2,
&callbacks, &ud));
CU_ASSERT(0 == spdylay_submit_headers(session, SPDYLAY_CTRL_FLAG_FIN, 1, nv));
item = spdylay_session_get_next_ob_item(session);
CU_ASSERT(0 == strcmp("version", item->frame->headers.nv[0]));
CU_ASSERT(0 == strcmp(":version", item->frame->headers.nv[0]));
CU_ASSERT(SPDYLAY_CTRL_FLAG_FIN == item->frame->headers.hd.flags);
ud.ctrl_send_cb_called = 0;
@ -754,6 +786,16 @@ void test_spdylay_submit_headers()
CU_ASSERT(SPDYLAY_HEADERS == ud.sent_frame_type);
CU_ASSERT(stream->shut_flags & SPDYLAY_SHUT_WR);
CU_ASSERT(0 == spdylay_frame_unpack_headers(&frame.headers,
&session->inflatebuf,
&session->nvbuf,
&session->nvbuflen,
&acc.buf[0], SPDYLAY_HEAD_LEN,
&acc.buf[SPDYLAY_HEAD_LEN],
acc.length-SPDYLAY_HEAD_LEN,
&session->hd_inflater));
CU_ASSERT(0 == strcmp("version", frame.headers.nv[0]));
spdylay_session_del(session);
}