diff --git a/lib/spdylay_frame.c b/lib/spdylay_frame.c index 3a94e79f..293375a3 100644 --- a/lib/spdylay_frame.c +++ b/lib/spdylay_frame.c @@ -901,6 +901,10 @@ ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr, { ssize_t framelen = SPDYLAY_FRAME_HEAD_LENGTH+frame->hd.length; int i, r; + if(frame->hd.version != SPDYLAY_PROTO_SPDY2 && + frame->hd.version != SPDYLAY_PROTO_SPDY3) { + return SPDYLAY_ERR_UNSUPPORTED_VERSION; + } r = spdylay_reserve_buffer(buf_ptr, buflen_ptr, framelen); if(r != 0) { return r; @@ -908,20 +912,29 @@ ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr, memset(*buf_ptr, 0, framelen); spdylay_frame_pack_ctrl_hd(*buf_ptr, &frame->hd); spdylay_put_uint32be(&(*buf_ptr)[8], frame->niv); - for(i = 0; i < frame->niv; ++i) { - int off = i*8; - /* spdy/2 spec says ID is network byte order, but publicly - deployed server sends little endian host byte order. */ - char *id_ptr = (char*)(&frame->iv[i].settings_id); + if(frame->hd.version == SPDYLAY_PROTO_SPDY2) { + for(i = 0; i < frame->niv; ++i) { + int off = i*8; + /* spdy/2 spec says ID is network byte order, but publicly + deployed server sends little endian host byte order. */ + char *id_ptr = (char*)(&frame->iv[i].settings_id); #ifdef WORDS_BIGENDIAN - (*buf_ptr)[12+off] = id_ptr[3]; - (*buf_ptr)[12+off+1] = id_ptr[2]; - (*buf_ptr)[12+off+2] = id_ptr[1]; + (*buf_ptr)[12+off] = id_ptr[3]; + (*buf_ptr)[12+off+1] = id_ptr[2]; + (*buf_ptr)[12+off+2] = id_ptr[1]; #else /* !WORDS_BIGENDIAN */ - memcpy(&(*buf_ptr)[12+off], id_ptr, 3); + memcpy(&(*buf_ptr)[12+off], id_ptr, 3); #endif /* !WORDS_BIGENDIAN */ - (*buf_ptr)[15+off] = frame->iv[i].flags; - spdylay_put_uint32be(&(*buf_ptr)[16+off], frame->iv[i].value); + (*buf_ptr)[15+off] = frame->iv[i].flags; + spdylay_put_uint32be(&(*buf_ptr)[16+off], frame->iv[i].value); + } + } else { + for(i = 0; i < frame->niv; ++i) { + int off = i*8; + spdylay_put_uint32be(&(*buf_ptr)[12+off], frame->iv[i].settings_id); + (*buf_ptr)[12+off] = frame->iv[i].flags; + spdylay_put_uint32be(&(*buf_ptr)[16+off], frame->iv[i].value); + } } return framelen; } @@ -935,6 +948,10 @@ int spdylay_frame_unpack_settings(spdylay_settings *frame, return SPDYLAY_ERR_INVALID_FRAME; } spdylay_frame_unpack_ctrl_hd(&frame->hd, head); + if(frame->hd.version != SPDYLAY_PROTO_SPDY2 && + frame->hd.version != SPDYLAY_PROTO_SPDY3) { + return SPDYLAY_ERR_UNSUPPORTED_VERSION; + } frame->niv = spdylay_get_uint32(payload); if(payloadlen != 4+frame->niv*8) { return SPDYLAY_ERR_INVALID_FRAME; @@ -943,20 +960,30 @@ int spdylay_frame_unpack_settings(spdylay_settings *frame, if(frame->iv == NULL) { return SPDYLAY_ERR_NOMEM; } - for(i = 0; i < frame->niv; ++i) { - int off = i*8; - /* ID is little endian. See comments in - spdylay_frame_pack_settings(). */ - frame->iv[i].settings_id = 0; + if(frame->hd.version == SPDYLAY_PROTO_SPDY2) { + for(i = 0; i < frame->niv; ++i) { + int off = i*8; + /* ID is little endian. See comments in + spdylay_frame_pack_settings(). */ + frame->iv[i].settings_id = 0; #ifdef WORDS_BIGENDIAN - *(char*)(&frame->iv[i].settings_id[1]) = &payload[4+off+2]; - *(char*)(&frame->iv[i].settings_id[2]) = &payload[4+off+1]; - *(char*)(&frame->iv[i].settings_id[3]) = &payload[4+off+0]; + *(char*)(&frame->iv[i].settings_id[1]) = &payload[4+off+2]; + *(char*)(&frame->iv[i].settings_id[2]) = &payload[4+off+1]; + *(char*)(&frame->iv[i].settings_id[3]) = &payload[4+off+0]; #else /* !WORDS_BIGENDIAN */ - memcpy(&frame->iv[i].settings_id, &payload[4+off], 3); + memcpy(&frame->iv[i].settings_id, &payload[4+off], 3); #endif /* !WORDS_BIGENDIAN */ - frame->iv[i].flags = payload[7+off]; - frame->iv[i].value = spdylay_get_uint32(&payload[8+off]); + frame->iv[i].flags = payload[7+off]; + frame->iv[i].value = spdylay_get_uint32(&payload[8+off]); + } + } else { + for(i = 0; i < frame->niv; ++i) { + int off = i*8; + frame->iv[i].settings_id = spdylay_get_uint32(&payload[4+off]) & + SPDYLAY_SETTINGS_ID_MASK; + frame->iv[i].flags = payload[4+off]; + frame->iv[i].value = spdylay_get_uint32(&payload[8+off]); + } } return 0; } diff --git a/lib/spdylay_frame.h b/lib/spdylay_frame.h index 1d0bde31..faa6b15e 100644 --- a/lib/spdylay_frame.h +++ b/lib/spdylay_frame.h @@ -37,6 +37,7 @@ #define SPDYLAY_LENGTH_MASK 0xffffff #define SPDYLAY_VERSION_MASK 0x7fff #define SPDYLAY_DELTA_WINDOW_SIZE_MASK 0x7fffffff +#define SPDYLAY_SETTINGS_ID_MASK 0xffffff /* The length of DATA frame payload. */ #define SPDYLAY_DATA_PAYLOAD_LENGTH 4096 @@ -353,6 +354,8 @@ int spdylay_frame_unpack_window_update(spdylay_window_update *frame, * This function returns the size of packed frame if it succeeds, or * returns one of the following negative error codes: * + * SPDYLAY_ERR_UNSUPPORTED_VERSION + * The version is not supported. * SPDYLAY_ERR_NOMEM * Out of memory. */ @@ -365,6 +368,8 @@ ssize_t spdylay_frame_pack_settings(uint8_t **buf_ptr, size_t *buflen_ptr, * This function returns 0 if it succeeds or one of the following * negative error codes: * + * SPDYLAY_ERR_UNSUPPORTED_VERSION + * The version is not supported. * SPDYLAY_ERR_INVALID_FRAME * The input data are invalid. * SPDYLAY_ERR_NOMEM diff --git a/tests/main.c b/tests/main.c index e87ef178..b8d5128e 100644 --- a/tests/main.c +++ b/tests/main.c @@ -165,8 +165,10 @@ int main(int argc, char* argv[]) test_spdylay_frame_pack_headers_spdy3) || !CU_add_test(pSuite, "frame_pack_window_update", test_spdylay_frame_pack_window_update) || - !CU_add_test(pSuite, "frame_pack_settings", - test_spdylay_frame_pack_settings) || + !CU_add_test(pSuite, "frame_pack_settings_spdy2", + test_spdylay_frame_pack_settings_spdy2) || + !CU_add_test(pSuite, "frame_pack_settings_spdy3", + test_spdylay_frame_pack_settings_spdy3) || !CU_add_test(pSuite, "frame_nv_sort", test_spdylay_frame_nv_sort) || !CU_add_test(pSuite, "frame_nv_downcase", test_spdylay_frame_nv_downcase) || diff --git a/tests/spdylay_frame_test.c b/tests/spdylay_frame_test.c index 94ea25cb..b0bc74d2 100644 --- a/tests/spdylay_frame_test.c +++ b/tests/spdylay_frame_test.c @@ -442,7 +442,7 @@ void test_spdylay_frame_pack_window_update() } -void test_spdylay_frame_pack_settings() +void test_spdylay_frame_pack_settings_version(uint16_t version) { spdylay_frame frame, oframe; uint8_t *buf = NULL; @@ -461,7 +461,7 @@ void test_spdylay_frame_pack_settings() iv[2].value = 65536; spdylay_frame_settings_init - (&frame.settings, SPDYLAY_PROTO_SPDY2, + (&frame.settings, version, SPDYLAY_FLAG_SETTINGS_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS, spdylay_frame_iv_copy(iv, 3), 3); framelen = spdylay_frame_pack_settings(&buf, &buflen, &frame.settings); @@ -473,7 +473,7 @@ void test_spdylay_frame_pack_settings() &buf[SPDYLAY_FRAME_HEAD_LENGTH], framelen-SPDYLAY_FRAME_HEAD_LENGTH)); - CU_ASSERT(SPDYLAY_PROTO_SPDY2 == oframe.settings.hd.version); + CU_ASSERT(version == oframe.settings.hd.version); CU_ASSERT(SPDYLAY_SETTINGS == oframe.settings.hd.type); CU_ASSERT(SPDYLAY_FLAG_SETTINGS_CLEAR_PREVIOUSLY_PERSISTED_SETTINGS == oframe.settings.hd.flags); @@ -491,6 +491,16 @@ void test_spdylay_frame_pack_settings() spdylay_frame_settings_free(&oframe.settings); } +void test_spdylay_frame_pack_settings_spdy2() +{ + test_spdylay_frame_pack_settings_version(SPDYLAY_PROTO_SPDY2); +} + +void test_spdylay_frame_pack_settings_spdy3() +{ + test_spdylay_frame_pack_settings_version(SPDYLAY_PROTO_SPDY3); +} + void test_spdylay_frame_nv_sort() { char *nv[7]; diff --git a/tests/spdylay_frame_test.h b/tests/spdylay_frame_test.h index 87673c31..a53aa4a4 100644 --- a/tests/spdylay_frame_test.h +++ b/tests/spdylay_frame_test.h @@ -40,7 +40,8 @@ void test_spdylay_frame_pack_syn_reply_spdy3(); void test_spdylay_frame_pack_headers_spdy2(); void test_spdylay_frame_pack_headers_spdy3(); void test_spdylay_frame_pack_window_update(); -void test_spdylay_frame_pack_settings(); +void test_spdylay_frame_pack_settings_spdy2(); +void test_spdylay_frame_pack_settings_spdy3(); void test_spdylay_frame_nv_sort(); void test_spdylay_frame_nv_downcase(); void test_spdylay_frame_nv_2to3();