int spdy_headers_parse(spdy_headers *headers, spdy_data *data, uint32_t frame_length, spdy_zlib_context *zlib_ctx) { int ret; size_t length = data->data_end - data->cursor; if(length < SPDY_HEADERS_MIN_LENGTH) { data->needed = SPDY_HEADERS_MIN_LENGTH - length; SPDYDEBUG("Not enough data for parsing the frame."); return SPDY_ERROR_INSUFFICIENT_DATA; } if((ret = spdy_headers_parse_header(headers, data)) != SPDY_ERROR_NONE) { SPDYDEBUG("Failed to parse header."); return ret; } /* Parse NV block. */ if((ret = spdy_nv_block_inflate_parse(headers->nv_block, data->cursor, frame_length, zlib_ctx)) != SPDY_ERROR_NONE) { /* Clean up. */ SPDYDEBUG("Failed to parse NV block."); return ret; } data->cursor += frame_length - SPDY_HEADERS_MIN_LENGTH; return SPDY_ERROR_NONE; }
/** * Parse a data frame * @param frame - Target data frame. * @param data - Data to parse. * @see spdy_data_frame * @return Errorcode */ int spdy_data_frame_parse(spdy_data_frame *frame, spdy_data *data) { int ret; size_t length; ret = spdy_data_frame_parse_header(frame, data); if(ret != SPDY_ERROR_NONE) { return ret; } length = data->data_end - data->cursor; if(frame->length > length) { data->needed = frame->length - length; SPDYDEBUG("Insufficient data for data frame."); return SPDY_ERROR_INSUFFICIENT_DATA; } frame->data = malloc(frame->length); if(!frame->data) { SPDYDEBUG("Frame payload malloc failed."); return SPDY_ERROR_MALLOC_FAILED; } memcpy(frame->data, data->cursor, frame->length); data->cursor += frame->length; return SPDY_ERROR_NONE; }
/* TODO: Test & documentation. Do not use yet! */ int spdy_nv_block_inflate_parse(spdy_nv_block *nv_block, unsigned char *data, size_t data_length, spdy_zlib_context *zlib_ctx) { int ret; /* Inflate NV block. */ char *inflate = NULL; size_t inflate_size = 0; if((ret = spdy_zlib_inflate(zlib_ctx, (char *)data, data_length, &inflate, &inflate_size)) != SPDY_ERROR_NONE) { SPDYDEBUG("Failed to inflate data."); return ret; } /* Parse NV block. */ ret = spdy_nv_block_parse(nv_block, (unsigned char *)inflate, inflate_size); free(inflate); if(ret != SPDY_ERROR_NONE) { /* Clean up. */ SPDYDEBUG("Failed to parse NV block."); return ret; } return SPDY_ERROR_NONE; }
/** * Parse a SYN_STREAM control frame. * Parses the header of a SYN_STREAM control frame and extracts the * NV block. * @param syn_stream - Destination frame. * @param hash - Streamid lookup * @param data - Data to parse. * @param frame_length - Length of the frame. * @see spdy_control_frame * @see SPDY_SYN_STREAM_MIN_LENGTH * @return 0 on success, -1 on failure. */ int spdy_syn_stream_parse(spdy_syn_stream *syn_stream, struct spindly_phys *phys, spdy_data *data, uint32_t frame_length) { int ret; size_t length = data->data_end - data->cursor; struct hashnode *hn; assert(phys != NULL); if(length < frame_length) { data->needed = frame_length - length; SPDYDEBUG("Not enough data for parsing the stream."); return SPDY_ERROR_INSUFFICIENT_DATA; } /* TODO: Optimize the double length check away. */ if(length < SPDY_SYN_STREAM_MIN_LENGTH) { data->needed = SPDY_SYN_STREAM_MIN_LENGTH - length; SPDYDEBUG("Not enough data for parsing the stream."); return SPDY_ERROR_INSUFFICIENT_DATA; } /* Parse the frame header. */ ret = spdy_syn_stream_parse_header(syn_stream, data); if(ret) { SPDYDEBUG("Failed to parse header."); return ret; } /* make sure the incoming streamid isn't already used */ hn = _spindly_hash_get(&phys->streamhash, syn_stream->stream_id); if(hn) { SPDYDEBUG("Got a SPDY_STREAM with an exiting id!"); return SPDY_ERROR_INVALID_DATA; } /* Init NV block. */ ret = spdy_nv_block_init(&syn_stream->nv_block); if(ret) return ret; /* Parse NV block. */ ret = spdy_nv_block_inflate_parse(&syn_stream->nv_block, data->cursor, frame_length, &phys->zlib_in); if(ret) { /* Clean up. */ SPDYDEBUG("Failed to parse NV block."); return ret; } data->cursor += frame_length - SPDY_SYN_STREAM_HEADER_MIN_LENGTH; return SPDY_ERROR_NONE; }
/** * Parse a SYN_STREAM control frame. * Parses the header of a SYN_STREAM control frame and extracts the * NV block. * @param syn_stream - Destination frame. * @param data - Data to parse. * @param frame_length - Length of the frame. * @param zlib_ctx - The zlib context to use. * @see spdy_control_frame * @see SPDY_SYN_STREAM_MIN_LENGTH * @return 0 on success, -1 on failure. */ int spdy_syn_stream_parse(spdy_syn_stream *syn_stream, spdy_data *data, uint32_t frame_length, spdy_zlib_context *zlib_ctx) { int ret; size_t length = data->data_end - data->cursor; if(length < frame_length) { data->needed = frame_length - length; SPDYDEBUG("Not enough data for parsing the stream."); return SPDY_ERROR_INSUFFICIENT_DATA; } /* TODO: Optimize the double length check away. */ if(length < SPDY_SYN_STREAM_MIN_LENGTH) { data->needed = SPDY_SYN_STREAM_MIN_LENGTH - length; SPDYDEBUG("Not enough data for parsing the stream."); return SPDY_ERROR_INSUFFICIENT_DATA; } /* Parse the frame header. */ if((ret = spdy_syn_stream_parse_header(syn_stream, data)) != SPDY_ERROR_NONE) { SPDYDEBUG("Failed to parse header."); return ret; } /* Init NV block. */ ret = spdy_nv_block_init(&syn_stream->nv_block); if(ret) { return ret; } /* Parse NV block. */ if((ret = spdy_nv_block_inflate_parse(&syn_stream->nv_block, data->cursor, frame_length, zlib_ctx)) != SPDY_ERROR_NONE) { /* Clean up. */ SPDYDEBUG("Failed to parse NV block."); return ret; } data->cursor += frame_length - SPDY_SYN_STREAM_HEADER_MIN_LENGTH; return SPDY_ERROR_NONE; }
int spdy_headers_parse_header(spdy_headers *headers, spdy_data *data) { size_t length = data->data_end - data->cursor; if(length < SPDY_HEADERS_MIN_LENGTH) { SPDYDEBUG("Not enough data for parsing the header."); data->needed = SPDY_HEADERS_MIN_LENGTH - length; return SPDY_ERROR_INSUFFICIENT_DATA; } headers->stream_id = BE_LOAD_32(data->cursor) & 0x7FFFFFFF; data->cursor += 4; return SPDY_ERROR_NONE; }
/** * Pack a Name/Value block into a payload for transmitting. * * Note that this function returns an allocated string in 'dest'. * * @param dest - Destination buffer. * @param dest_size - Pointer for storing the size of the destination buffer. * @param nv_block - NV block to pack. * @see spdy_nv_block * @see spdy_nv_block_parse * @todo Multiple value support. * @return 0 on success, -1 on failure. */ int spdy_nv_block_pack(char **dest, size_t *dest_size, spdy_nv_block *nv_block) { int i; char *cursor; *dest = NULL; /* Two bytes for the number of pairs. */ *dest_size = 2; /* Calculate the size needed for the ouput buffer. */ for(i = 0; i < nv_block->count; i++) { /* Two bytes (length) + stringlength */ *dest_size += 2 + strlen(nv_block->pairs[i].name); *dest_size += 2 + strlen(nv_block->pairs[i].values); } /* Allocate memory for dest */ *dest = malloc(*dest_size); if(!*dest) { SPDYDEBUG("Memoy allocation failed."); return SPDY_ERROR_MALLOC_FAILED; } /* Cursor always points to the location in dest where we're working. */ cursor = *dest; /* 2-bytes for the number of NV-pairs that follow. */ BE_STORE_16(cursor, nv_block->count); cursor += 2; for(i = 0; i < nv_block->count; i++) { uint16_t length; /* Read the length and copy the data of each name/value into the * destination buffer. */ length = strlen(nv_block->pairs[i].name); BE_STORE_16(cursor, length); memcpy(cursor + 2, nv_block->pairs[i].name, length); cursor += length + 2; length = strlen(nv_block->pairs[i].values); BE_STORE_16(cursor, length); memcpy(cursor + 2, nv_block->pairs[i].values, length); cursor += length + 2; } return SPDY_ERROR_NONE; }
/** * Parse the header of a SYN_STREAM control frame. * This function can be used to parse the header of a SYN_STREAM frame * before the whole NV block has been received. (Minimum of bytes needed * is stored in SPDY_SYN_STREAM_HEADER_MIN_LENGTH.) * @param syn_stream - Destination frame. * @param data - Data to parse. * @see SPDY_SYN_STREAM_HEADER_MIN_LENGTH * @return Errorcode */ int spdy_syn_stream_parse_header(spdy_syn_stream *syn_stream, spdy_data *data) { size_t length = data->data_end - data->cursor; if(length < SPDY_SYN_STREAM_HEADER_MIN_LENGTH) { SPDYDEBUG("Not enough data for parsing the header."); data->needed = SPDY_SYN_STREAM_HEADER_MIN_LENGTH - length; return SPDY_ERROR_INSUFFICIENT_DATA; } /* Read the Stream-ID. */ syn_stream->stream_id = BE_LOAD_32(data->cursor) & 0x7FFFFFFF; data->cursor += 4; /* Read the 'Associated-To-Stream-ID'. */ syn_stream->associated_to = BE_LOAD_32(data->cursor) & 0x7FFFFFFF; data->cursor += 4; /* Read the two priority bits. */ syn_stream->priority = (data->cursor[0] & 0xC0) >> 6; /* Skip the unused block. */ data->cursor += 2; return SPDY_ERROR_NONE; }
/** * Parse the header of a data frame. This needs 'stream_id' to be cleared to * consider this as the first call. * * @param frame - Target data frame. * @param data - Data to parse. * @see spdy_data_frame * @return Errorcode */ int spdy_data_frame_parse_header(spdy_data_frame *frame, spdy_data *data) { /* Check if the frame header has already been parsed. */ if(!frame->stream_id) { size_t length = data->data_end - data->cursor; if(length < SPDY_DATA_FRAME_MIN_LENGTH) { SPDYDEBUG("Insufficient data for data frame."); data->needed = SPDY_DATA_FRAME_MIN_LENGTH - length; return SPDY_ERROR_INSUFFICIENT_DATA; } /* Read stream id. (AND removes the first type bit.) */ frame->stream_id = BE_LOAD_32(data->cursor) & 0x7FFFFFFF; data->cursor += 4; frame->flags = data->cursor[0]; frame->length = BE_LOAD_32(data->cursor) & 0x00FFFFFF; data->cursor += 4; frame->data = NULL; /* no frame payload yet */ } return SPDY_ERROR_NONE; }
/** * Parse a Name/Value block payload. * @param block - Target block. * @param data - Data to parse. * @param data_length - Length of data. * @see spdy_nv_block * @todo Replace mallocs with a single one. (Speed up!) * @todo Freeing in the loop. * @todo Multiple value support. * @return Errorcode */ int spdy_nv_block_parse(spdy_nv_block *block, unsigned char *data, size_t data_length) { /* The bounds of data. */ unsigned char *data_max = data + data_length; /* For the for-loop: */ /* Parsing block pair count */ if(!block->has_count) { /* Data must at least contain the number of NV pairs. */ if(data_length < 2) { SPDYDEBUG("Data to small."); return SPDY_ERROR_INSUFFICIENT_DATA; } /* Read the 16 bit integer containing the number of name/value pairs. */ block->count = BE_LOAD_16(data); block->has_count = 1; block->pairs_parsed = 0; /* Move forward by two bytes. */ data += 2; if(block->count == 0) { block->pairs = NULL; return SPDY_ERROR_NONE; } /* Allocate memory for Name/Value pairs. */ block->pairs = calloc(block->count, sizeof(spdy_nv_pair)); /* Malloc failed */ if(!block->pairs) { SPDYDEBUG("Malloc of pairs failed."); return SPDY_ERROR_MALLOC_FAILED; } } /* End of parsing block pair count */ /* Loop through all pairs */ for(; block->pairs_parsed < block->count; block->pairs_parsed++) { size_t size; spdy_nv_pair *pair; uint16_t tmp_item_length; if(data + 2 > data_max) { SPDYDEBUG("Data to small."); return SPDY_ERROR_INSUFFICIENT_DATA; } pair = &block->pairs[block->pairs_parsed]; /* Read Name */ /* Read length of name */ tmp_item_length = BE_LOAD_16(data); data += 2; /* Allocate space for name */ size = tmp_item_length + 1; if(data + tmp_item_length > data_max) { SPDYDEBUG("Data to small."); return SPDY_ERROR_INSUFFICIENT_DATA; } pair->name = malloc(size); if(!pair->name) { SPDYDEBUG("Pair name malloc failed."); return SPDY_ERROR_MALLOC_FAILED; } memcpy(pair->name, data, tmp_item_length); pair->name[tmp_item_length] = '\0'; data += tmp_item_length; /* End of read name */ /* Read Values */ /* TODO: Support multiple values. */ /* Read length of value */ if(data + 2 > data_max) { SPDYDEBUG("Data to small."); free(pair->name); return SPDY_ERROR_INSUFFICIENT_DATA; } tmp_item_length = BE_LOAD_16(data); data += 2; /* Allocate space for values */ size = tmp_item_length + 1; if(data + tmp_item_length > data_max) { SPDYDEBUG("Insufficient data for block parse."); free(pair->name); return SPDY_ERROR_INSUFFICIENT_DATA; } pair->values = malloc(size); if(!pair->values) { SPDYDEBUG("Pair value malloc failed."); free(pair->name); return SPDY_ERROR_MALLOC_FAILED; } memcpy(pair->values, data, tmp_item_length); pair->values[tmp_item_length] = '\0'; data += tmp_item_length; /* End of read value */ } return SPDY_ERROR_NONE; }