14e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)// Copyright 2013 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 54e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/balsa_frame.h" 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// Visual C++ defines _M_IX86_FP as 2 if the /arch:SSE2 compiler option is 8116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch// specified. 9116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#if !defined(__SSE2__) && _M_IX86_FP == 2 10116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#define __SSE2__ 1 11116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#endif 12116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h> 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if __SSE2__ 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <emmintrin.h> 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // __SSE2__ 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <limits> 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <utility> 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <vector> 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h" 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/port.h" 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/strings/string_piece.h" 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/balsa_enums.h" 274e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/balsa_headers.h" 284e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/balsa_visitor_interface.h" 294e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/buffer_interface.h" 304e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/simple_buffer.h" 314e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/split.h" 324e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)#include "net/tools/balsa/string_piece_utils.h" 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 34f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#if defined(COMPILER_MSVC) 35116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#include <intrin.h> 36f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <string.h> 37116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 38116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch#pragma intrinsic(_BitScanForward) 39116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 40116680a4aac90f2aa7413d9095a592090648e557Ben Murdochstatic int ffs(int i) { 41116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch unsigned long index; 42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch return _BitScanForward(&index, i) ? index + 1 : 0; 43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch} 44116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch 45f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#define strncasecmp _strnicmp 46f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#else 47f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#include <strings.h> 48f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)#endif 49f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Constants holding some header names for headers which can affect the way the 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// HTTP message is framed, and so must be processed specially: 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kContentLength[] = "content-length"; 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kContentLengthSize = sizeof(kContentLength) - 1; 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const char kTransferEncoding[] = "transfer-encoding"; 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static const size_t kTransferEncodingSize = sizeof(kTransferEncoding) - 1; 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BalsaFrame::BalsaFrame() 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) : last_char_was_slash_r_(false), 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_non_newline_char_(false), 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_was_space_(true), 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_character_extracted_(false), 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_request_(true), 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) request_was_head_(false), 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_header_length_(16 * 1024), 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_request_uri_length_(2048), 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_(&do_nothing_visitor_), 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_remaining_(0), 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_remaining_(0), 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_loc_(NULL), 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_recorded_slash_n_loc_(NULL), 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_idx_(0), 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) term_chars_(0), 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE), 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_(BalsaFrameEnums::NO_ERROR), 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_(NULL) { 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BalsaFrame::~BalsaFrame() {} 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::Reset() { 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_char_was_slash_r_ = false; 845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_non_newline_char_ = false; 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) start_was_space_ = true; 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_character_extracted_ = false; 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is_request_ = true; // not reset between messages. 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // request_was_head_ = false; // not reset between messages. 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // max_header_length_ = 4096; // not reset between messages. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // max_request_uri_length_ = 2048; // not reset between messages. 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // visitor_ = &do_nothing_visitor_; // not reset between messages. 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_remaining_ = 0; 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_remaining_ = 0; 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_loc_ = NULL; 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_recorded_slash_n_loc_ = NULL; 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_idx_ = 0; 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) term_chars_ = 0; 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE; 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::NO_ERROR; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines_.clear(); 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers_ != NULL) { 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->Clear(); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BalsaFrameEnums::ParseStateToString( 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::ParseState error_code) { 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (error_code) { 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case PARSE_ERROR: 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return "PARSE_ERROR"; 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_HEADER_AND_FIRSTLINE: 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_HEADER_AND_FIRSTLINE"; 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_CHUNK_LENGTH: 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_CHUNK_LENGTH"; 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_CHUNK_EXTENSION: 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_CHUNK_EXTENSION"; 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_CHUNK_DATA: 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_CHUNK_DATA"; 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_CHUNK_TERM: 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_CHUNK_TERM"; 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_LAST_CHUNK_TERM: 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_LAST_CHUNK_TERM"; 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_TRAILER: 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_TRAILER"; 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_UNTIL_CLOSE: 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_UNTIL_CLOSE"; 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case READING_CONTENT: 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "READING_CONTENT"; 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MESSAGE_FULLY_READ: 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "MESSAGE_FULLY_READ"; 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case NUM_STATES: 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "UNKNOWN_STATE"; 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "UNKNOWN_STATE"; 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)const char* BalsaFrameEnums::ErrorCodeToString( 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::ErrorCode error_code) { 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (error_code) { 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case NO_ERROR: 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "NO_ERROR"; 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case NO_STATUS_LINE_IN_RESPONSE: 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "NO_STATUS_LINE_IN_RESPONSE"; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case NO_REQUEST_LINE_IN_REQUEST: 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "NO_REQUEST_LINE_IN_REQUEST"; 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION: 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION"; 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case FAILED_TO_FIND_WS_AFTER_REQUEST_METHOD: 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "FAILED_TO_FIND_WS_AFTER_REQUEST_METHOD"; 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case FAILED_TO_FIND_WS_AFTER_RESPONSE_STATUSCODE: 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "FAILED_TO_FIND_WS_AFTER_RESPONSE_STATUSCODE"; 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case FAILED_TO_FIND_WS_AFTER_REQUEST_REQUEST_URI: 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "FAILED_TO_FIND_WS_AFTER_REQUEST_REQUEST_URI"; 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case FAILED_TO_FIND_NL_AFTER_RESPONSE_REASON_PHRASE: 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "FAILED_TO_FIND_NL_AFTER_RESPONSE_REASON_PHRASE"; 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case FAILED_TO_FIND_NL_AFTER_REQUEST_HTTP_VERSION: 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "FAILED_TO_FIND_NL_AFTER_REQUEST_HTTP_VERSION"; 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case FAILED_CONVERTING_STATUS_CODE_TO_INT: 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "FAILED_CONVERTING_STATUS_CODE_TO_INT"; 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case REQUEST_URI_TOO_LONG: 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "REQUEST_URI_TOO_LONG"; 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HEADERS_TOO_LONG: 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "HEADERS_TOO_LONG"; 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case UNPARSABLE_CONTENT_LENGTH: 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "UNPARSABLE_CONTENT_LENGTH"; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MAYBE_BODY_BUT_NO_CONTENT_LENGTH: 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "MAYBE_BODY_BUT_NO_CONTENT_LENGTH"; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case REQUIRED_BODY_BUT_NO_CONTENT_LENGTH: 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "REQUIRED_BODY_BUT_NO_CONTENT_LENGTH"; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case HEADER_MISSING_COLON: 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "HEADER_MISSING_COLON"; 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case INVALID_CHUNK_LENGTH: 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "INVALID_CHUNK_LENGTH"; 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CHUNK_LENGTH_OVERFLOW: 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "CHUNK_LENGTH_OVERFLOW"; 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CALLED_BYTES_SPLICED_WHEN_UNSAFE_TO_DO_SO: 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "CALLED_BYTES_SPLICED_WHEN_UNSAFE_TO_DO_SO"; 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT: 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT"; 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MULTIPLE_CONTENT_LENGTH_KEYS: 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "MULTIPLE_CONTENT_LENGTH_KEYS"; 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case MULTIPLE_TRANSFER_ENCODING_KEYS: 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "MULTIPLE_TRANSFER_ENCODING_KEYS"; 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case UNKNOWN_TRANSFER_ENCODING: 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "UNKNOWN_TRANSFER_ENCODING"; 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case INVALID_HEADER_FORMAT: 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "INVALID_HEADER_FORMAT"; 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case INTERNAL_LOGIC_ERROR: 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "INTERNAL_LOGIC_ERROR"; 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case NUM_ERROR_CODES: 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "UNKNOWN_ERROR"; 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return "UNKNOWN_ERROR"; 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Summary: 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Parses the first line of either a request or response. 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that in the case of a detected warning, error_code will be set 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// but the function will not return false. 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Exactly zero or one warning or error (but not both) may be detected 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// by this function. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Note that this function will not write the data of the first-line 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// into the header's buffer (that should already have been done elsewhere). 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Pre-conditions: 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// begin != end 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// *begin should be a character which is > ' '. This implies that there 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// is at least one non-whitespace characters between [begin, end). 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// headers is a valid pointer to a BalsaHeaders class. 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error_code is a valid pointer to a BalsaFrameEnums::ErrorCode value. 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Entire first line must exist between [begin, end) 2125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Exactly zero or one newlines -may- exist between [begin, end) 2135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [begin, end) should exist in the header's buffer. 2145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Side-effects: 2165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// headers will be modified 2175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// error_code may be modified if either a warning or error is detected 2185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Returns: 2205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// True if no error (as opposed to warning) is detected. 2215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// False if an error (as opposed to warning) is detected. 2225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// If there is indeed non-whitespace in the line, then the following 2255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// will take care of this for you: 2265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// while (*begin <= ' ') ++begin; 2275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ProcessFirstLine(begin, end, is_request, &headers, &error_code); 2285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool ParseHTTPFirstLine(const char* begin, 2305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* end, 2315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool is_request, 2325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t max_request_uri_length, 2335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaHeaders* headers, 2345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::ErrorCode* error_code) { 2355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* current = begin; 2365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // HTTP firstlines all have the following structure: 2375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // LWS NONWS LWS NONWS LWS NONWS NOTCRLF CRLF 2385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [\t \r\n]+ [^\t ]+ [\t ]+ [^\t ]+ [\t ]+ [^\t ]+ [^\r\n]+ "\r\n" 2395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ws1 nws1 ws2 nws2 ws3 nws3 ws4 2405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // | [-------) [-------) [----------------) 2415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // REQ: method request_uri version 2425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // RESP: version statuscode reason 2435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The first NONWS->LWS component we'll call firstline_a. 2455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The second firstline_b, and the third firstline_c. 2465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // firstline_a goes from nws1 to (but not including) ws2 2485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // firstline_b goes from nws2 to (but not including) ws3 2495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // firstline_c goes from nws3 to (but not including) ws4 2505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In the code: 2525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ws1 == whitespace_1_idx_ 2535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // nws1 == non_whitespace_1_idx_ 2545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ws2 == whitespace_2_idx_ 2555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // nws2 == non_whitespace_2_idx_ 2565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ws3 == whitespace_3_idx_ 2575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // nws3 == non_whitespace_3_idx_ 2585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ws4 == whitespace_4_idx_ 2595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Kill all whitespace (including '\r\n') at the end of the line. 2615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --end; 2625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*end != '\n') { 2635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = BalsaFrameEnums::INTERNAL_LOGIC_ERROR; 2645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(DFATAL) << "INTERNAL_LOGIC_ERROR Headers: \n" 2655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << headers->OriginalHeadersForDebugging(); 2665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (begin < end && *end <= ' ') { 2695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --end; 2705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(*end != '\n'); 2725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*end == '\n') { 2735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = BalsaFrameEnums::INTERNAL_LOGIC_ERROR; 2745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(DFATAL) << "INTERNAL_LOGIC_ERROR Headers: \n" 2755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << headers->OriginalHeadersForDebugging(); 2765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++end; 2795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The two following statements should not be possible. 2815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (end == begin) { 2825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = BalsaFrameEnums::INTERNAL_LOGIC_ERROR; 2835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(DFATAL) << "INTERNAL_LOGIC_ERROR Headers: \n" 2845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << headers->OriginalHeadersForDebugging(); 2855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 2865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whitespace_1_idx_ 2895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_1_idx_ = current - begin; 2905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This loop is commented out as it is never used in current code. This is 2915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // true only because we don't begin parsing the headers at all until we've 2925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // encountered a non whitespace character at the beginning of the stream, at 2935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which point we begin our demarcation of header-start. If we did -not- do 2945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this (for instance, only looked for [\r\n] instead of (< ' ')), this loop 2955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // would be necessary for the proper functioning of this parsing. 2965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is left here as this function may (in the future) be refactored out 2975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of the BalsaFrame class so that it may be shared between code in 2985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // BalsaFrame and BalsaHeaders (where it would be used in some variant of the 2995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // set_first_line() function (at which point it would be necessary). 3005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if 0 3015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*current <= ' ') { 3025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 3035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 3055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // non_whitespace_1_idx_ 3065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->non_whitespace_1_idx_ = current - begin; 3075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 3085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The first time through, we're guaranteed that the current character 3095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // won't be a whitespace (else the loop above wouldn't have terminated). 3105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // That implies that we're guaranteed to get at least one non-whitespace 3115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // character if we get into this loop at all. 3125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 3135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current == end) { 3145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_2_idx_ = current - begin; 3155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->non_whitespace_2_idx_ = current - begin; 3165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_3_idx_ = current - begin; 3175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->non_whitespace_3_idx_ = current - begin; 3185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_4_idx_ = current - begin; 3195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FAILED_TO_FIND_WS_AFTER_REQUEST_METHOD for request 3205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION for response 3215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = 3225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<BalsaFrameEnums::ErrorCode>( 3235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION + 3245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_request); 3255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!is_request) { // FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION 3265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto output_exhausted; 3295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (*current > ' '); 3315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whitespace_2_idx_ 3325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_2_idx_ = current - begin; 3335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 3345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 3355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that due to the loop which consumes all of the whitespace 3365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // at the end of the line, current can never == end while in this function. 3375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (*current <= ' '); 3385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // non_whitespace_2_idx_ 3395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->non_whitespace_2_idx_ = current - begin; 3405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 3415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 3425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current == end) { 3435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_3_idx_ = current - begin; 3445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->non_whitespace_3_idx_ = current - begin; 3455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_4_idx_ = current - begin; 3465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FAILED_TO_FIND_START_OF_REQUEST_REQUEST_URI for request 3475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // FAILED_TO_FIND_START_OF_RESPONSE_STATUSCODE for response 3485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = 3495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<BalsaFrameEnums::ErrorCode>( 3505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::FAILED_TO_FIND_WS_AFTER_RESPONSE_STATUSCODE 3515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) + is_request); 3525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto output_exhausted; 3535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (*current > ' '); 3555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // whitespace_3_idx_ 3565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_3_idx_ = current - begin; 3575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 3585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 3595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that due to the loop which consumes all of the whitespace 3605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // at the end of the line, current can never == end while in this function. 3615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (*current <= ' '); 3625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // non_whitespace_3_idx_ 3635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->non_whitespace_3_idx_ = current - begin; 3645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->whitespace_4_idx_ = end - begin; 3655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) output_exhausted: 3675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that we don't fail the parse immediately when parsing of the 3685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // firstline fails. Depending on the protocol type, we may want to accept 3695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a firstline with only one or two elements, e.g., for HTTP/0.9: 3705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GET\r\n 3715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or 3725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // GET /\r\n 3735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // should be parsed without issue (though the visitor should know that 3745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // parsing the entire line was not exactly as it should be). 3755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 3765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Eventually, these errors may be removed alltogether, as the visitor can 3775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // detect them on its own by examining the size of the various fields. 3785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // headers->set_first_line(non_whitespace_1_idx_, current); 3795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_request) { 3815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((headers->whitespace_3_idx_ - headers->non_whitespace_2_idx_) > 3825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_request_uri_length) { 3835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For requests, we need at least the method. We could assume that a 3845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // blank URI means "/". If version isn't stated, it should be assumed 3855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to be HTTP/0.9 by the visitor. 3865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = BalsaFrameEnums::REQUEST_URI_TOO_LONG; 3875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 3885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 3895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 3905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->parsed_response_code_ = 0; 3915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 3925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* parsed_response_code_current = 3935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers->non_whitespace_2_idx_; 3945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* parsed_response_code_end = begin + headers->whitespace_3_idx_; 3955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t kMaxDiv10 = std::numeric_limits<size_t>::max() / 10; 3965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 3975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Convert a string of [0-9]* into an int. 3985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that this allows for the conversion of response codes which 3995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are outside the bounds of normal HTTP response codes (no checking 4005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is done to ensure that these are valid-- they're merely parsed)! 4015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (parsed_response_code_current < parsed_response_code_end) { 4025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*parsed_response_code_current < '0' || 4035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *parsed_response_code_current > '9') { 4045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = BalsaFrameEnums::FAILED_CONVERTING_STATUS_CODE_TO_INT; 4055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t status_code_x_10 = headers->parsed_response_code_ * 10; 4085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) uint8 c = *parsed_response_code_current - '0'; 4095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((headers->parsed_response_code_ > kMaxDiv10) || 4105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (std::numeric_limits<size_t>::max() - status_code_x_10) < c) { 4115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // overflow. 4125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *error_code = BalsaFrameEnums::FAILED_CONVERTING_STATUS_CODE_TO_INT; 4135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 4145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers->parsed_response_code_ = status_code_x_10 + c; 4165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++parsed_response_code_current; 4175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 4215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// begin - beginning of the firstline 4245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// end - end of the firstline 4255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A precondition for this function is that there is non-whitespace between 4275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// [begin, end). If this precondition is not met, the function will not perform 4285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// as expected (and bad things may happen, and it will eat your first, second, 4295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// and third unborn children!). 4305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Another precondition for this function is that [begin, end) includes 4325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// at most one newline, which must be at the end of the line. 4335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::ProcessFirstLine(const char* begin, const char* end) { 4345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::ErrorCode previous_error = last_error_; 4355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!ParseHTTPFirstLine(begin, 4365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) end, 4375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) is_request_, 4385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) max_request_uri_length_, 4395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_, 4405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) &last_error_)) { 4415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 4425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 4435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 4445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (previous_error != last_error_) { 4465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderWarning(this); 4475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_request_) { 450f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) size_t version_length = 4515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_4_idx_ - headers_->non_whitespace_3_idx_; 4525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessRequestFirstLine( 4535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_1_idx_, 4545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_4_idx_ - headers_->non_whitespace_1_idx_, 4555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_1_idx_, 4565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_2_idx_ - headers_->non_whitespace_1_idx_, 4575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_2_idx_, 4585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_3_idx_ - headers_->non_whitespace_2_idx_, 4595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_3_idx_, 4605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) version_length); 4615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (version_length == 0) 4625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 4635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 4645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessResponseFirstLine( 4655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_1_idx_, 4665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_4_idx_ - headers_->non_whitespace_1_idx_, 4675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_1_idx_, 4685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_2_idx_ - headers_->non_whitespace_1_idx_, 4695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_2_idx_, 4705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_3_idx_ - headers_->non_whitespace_2_idx_, 4715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) begin + headers_->non_whitespace_3_idx_, 4725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->whitespace_4_idx_ - headers_->non_whitespace_3_idx_); 4735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 4745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 4755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'stream_begin' points to the first character of the headers buffer. 4775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'line_begin' points to the first character of the line. 4785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'current' points to a char which is ':'. 4795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'line_end' points to the position of '\n' + 1. 4805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 'line_begin' points to the position of first character of line. 4815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::CleanUpKeyValueWhitespace( 4825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* stream_begin, 4835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_begin, 4845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* current, 4855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_end, 4865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeaderLineDescription* current_header_line) { 4875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* colon_loc = current; 4885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(colon_loc, line_end); 4895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(':', *colon_loc); 4905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(':', *current); 4915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(' ', *line_end) 4925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "\"" << std::string(line_begin, line_end) << "\""; 4935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 4945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(fenix): Investigate whether or not the bounds tests in the 4955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // while loops here are redundant, and if so, remove them. 4965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --current; 4975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current > line_begin && *current <= ' ') --current; 4985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current += (current != colon_loc); 4995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_header_line->key_end_idx = current - stream_begin; 5005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current = colon_loc; 5025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(':', *current); 5035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 5045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < line_end && *current <= ' ') ++current; 5055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_header_line->value_begin_idx = current - stream_begin; 5065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(current_header_line->key_end_idx, 5085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_header_line->first_char_idx); 5095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(current_header_line->value_begin_idx, 5105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_header_line->key_end_idx); 5115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(current_header_line->last_char_idx, 5125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_header_line->value_begin_idx); 5135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 5145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)inline void BalsaFrame::FindColonsAndParseIntoKeyValue() { 5165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!lines_.empty()); 5175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* stream_begin = headers_->OriginalHeaderStreamBegin(); 5185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The last line is always just a newline (and is uninteresting). 5195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const Lines::size_type lines_size_m1 = lines_.size() - 1; 5205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if __SSE2__ 521116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch const __m128i colons = _mm_set1_epi8(':'); 5225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* header_lines_end_m16 = headers_->OriginalHeaderStreamEnd() - 16; 5235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // __SSE2__ 5245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* current = stream_begin + lines_[1].first; 5255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This code is a bit more subtle than it may appear at first glance. 5265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This code looks for a colon in the current line... but it also looks 5275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // beyond the current line. If there is no colon in the current line, then 5285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for each subsequent line (until the colon which -has- been found is 5295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // associated with a line), no searching for a colon will be performed. In 5305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // this way, we minimize the amount of bytes we have scanned for a colon. 5315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (Lines::size_type i = 1; i < lines_size_m1;) { 5325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_begin = stream_begin + lines_[i].first; 5335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Here we handle possible continuations. Note that we do not replace 5355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the '\n' in the line before a continuation (at least, as of now), 5365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which implies that any code which looks for a value must deal with 5375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "\r\n", etc -within- the line (and not just at the end of it). 5385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (++i; i < lines_size_m1; ++i) { 5395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *(stream_begin + lines_[i].first); 5405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c > ' ') { 5415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Not a continuation, so stop. Note that if the 'original' i = 1, 5425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and the next line is not a continuation, we'll end up with i = 2 5435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // when we break. This handles the incrementing of i for the outer 5445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // loop. 5455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 5465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_end = stream_begin + lines_[i - 1].second; 5495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(line_begin - stream_begin, line_end - stream_begin); 5505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We cleanup the whitespace at the end of the line before doing anything 5525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // else of interest as it allows us to do nothing when irregularly formatted 5535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // headers are parsed (e.g. those with only keys, only values, or no colon). 5545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 5555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We're guaranteed to have *line_end > ' ' while line_end >= line_begin. 5565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --line_end; 5575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ('\n', *line_end) 5585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "\"" << std::string(line_begin, line_end) << "\""; 5595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (*line_end <= ' ' && line_end > line_begin) { 5605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --line_end; 5615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++line_end; 5635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_GE(' ', *line_end); 5645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LT(line_begin, line_end); 5655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 5665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We use '0' for the block idx, because we're always writing to the first 5675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // block from the framer (we do this because the framer requires that the 5685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // entire header sequence be in a contiguous buffer). 5695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->header_lines_.push_back( 5705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeaderLineDescription(line_begin - stream_begin, 5715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_end - stream_begin, 5725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_end - stream_begin, 5735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_end - stream_begin, 5745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0)); 5755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current >= line_end) { 5765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::HEADER_MISSING_COLON; 5775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderWarning(this); 5785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Then the next colon will not be found within this header line-- time 5795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to try again with another header-line. 5805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 5815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (current < line_begin) { 5825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // When this condition is true, the last detected colon was part of a 5835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // previous line. We reset to the beginning of the line as we don't care 5845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // about the presence of any colon before the beginning of the current 5855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // line. 5865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current = line_begin; 5875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if __SSE2__ 5895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < header_lines_end_m16) { 5905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __m128i header_bytes = 5915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _mm_loadu_si128(reinterpret_cast<const __m128i *>(current)); 592116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch __m128i colon_cmp = _mm_cmpeq_epi8(header_bytes, colons); 5935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int colon_msk = _mm_movemask_epi8(colon_cmp); 5945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (colon_msk == 0) { 5955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current += 16; 5965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 5975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 5985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current += (ffs(colon_msk) - 1); 5995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current > line_end) { 6005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 6015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto found_colon; 6035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // __SSE2__ 6055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (; current < line_end; ++current) { 6065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*current != ':') { 6075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 6085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto found_colon; 6105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we've gotten to here, then there was no colon 6125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // in the line. The arguments we passed into the construction 6135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the HeaderLineDescription object should be OK-- it assumes 6145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that the entire content is 'key' by default (which is true, as 6155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there was no colon, there can be no value). Note that this is a 6165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // construct which is technically not allowed by the spec. 6175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::HEADER_MISSING_COLON; 6185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderWarning(this); 6195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 6205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) found_colon: 6215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_EQ(*current, ':'); 6225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(current - stream_begin, line_end - stream_begin); 6235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK_LE(stream_begin - stream_begin, current - stream_begin); 6245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeaderLineDescription& current_header_line = headers_->header_lines_.back(); 6265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_header_line.key_end_idx = current - stream_begin; 6275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current_header_line.value_begin_idx = current_header_line.key_end_idx; 6285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (current < line_end) { 6295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current_header_line.key_end_idx; 6305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) CleanUpKeyValueWhitespace(stream_begin, 6325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_begin, 6335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current, 6345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) line_end, 6355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ¤t_header_line); 6365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::ProcessContentLengthLine( 6415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeaderLines::size_type line_idx, 6425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaHeadersEnums::ContentLengthStatus* status, 6435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t* length) { 6445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HeaderLineDescription& header_line = headers_->header_lines_[line_idx]; 6455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* stream_begin = headers_->OriginalHeaderStreamBegin(); 6465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_end = stream_begin + header_line.last_char_idx; 6475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* value_begin = (stream_begin + header_line.value_begin_idx); 6485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (value_begin >= line_end) { 6505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no non-whitespace value data. 6515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 6525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "invalid content-length -- no non-whitespace value data"; 6535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 6545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH; 6555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *length = 0; 6595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (value_begin < line_end) { 6605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*value_begin < '0' || *value_begin > '9') { 6615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // bad! content-length found, and couldn't parse all of it! 6625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH; 6635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 6645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "invalid content-length - non numeric character detected"; 6655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 6665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t kMaxDiv10 = std::numeric_limits<size_t>::max() / 10; 6695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t length_x_10 = *length * 10; 6705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const unsigned char c = *value_begin - '0'; 6715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*length > kMaxDiv10 || 6725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (std::numeric_limits<size_t>::max() - length_x_10) < c) { 6735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *status = BalsaHeadersEnums::CONTENT_LENGTH_OVERFLOW; 6745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 6755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "content-length overflow"; 6765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 6775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 6785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *length = length_x_10 + c; 6805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++value_begin; 6815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 6825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 6835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "content_length parsed: " << *length; 6845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 6855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *status = BalsaHeadersEnums::VALID_CONTENT_LENGTH; 6865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 6875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::ProcessTransferEncodingLine(HeaderLines::size_type line_idx) { 6895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HeaderLineDescription& header_line = headers_->header_lines_[line_idx]; 6905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* stream_begin = headers_->OriginalHeaderStreamBegin(); 6915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* line_end = stream_begin + header_line.last_char_idx; 6925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* value_begin = stream_begin + header_line.value_begin_idx; 6935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t value_length = line_end - value_begin; 6945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 6955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((value_length == 7) && 6965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strncasecmp(value_begin, "chunked", 7)) { 6975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->transfer_encoding_is_chunked_ = true; 6985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if ((value_length == 8) && 6995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !strncasecmp(value_begin, "identity", 8)) { 7005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->transfer_encoding_is_chunked_ = false; 7015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::UNKNOWN_TRANSFER_ENCODING; 7035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 7045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 7055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 7065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace { 7105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool SplitStringPiece(base::StringPiece original, char delim, 7115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece* before, base::StringPiece* after) { 7125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* p = original.data(); 7135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* end = p + original.size(); 7145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (p != end) { 7165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*p == delim) { 7175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++p; 7185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 7195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* start = p; 7205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (++p != end && *p != delim) { 7215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Skip to the next occurence of the delimiter. 7225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *before = base::StringPiece(start, p - start); 7245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (p != end) 7255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *after = base::StringPiece(p + 1, end - (p + 1)); 7265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else 7275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *after = base::StringPiece(""); 7285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringPieceUtils::RemoveWhitespaceContext(before); 7295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringPieceUtils::RemoveWhitespaceContext(after); 7305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return true; 7315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *before = original; 7355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) *after = ""; 7365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return false; 7375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// TODO(phython): Fix this function to properly deal with quoted values. 7405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// E.g. ";;foo", "\";;\"", or \"aa; 7415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The last example, the semi-colon is a separator between extensions. 7425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ProcessChunkExtensionsManual(base::StringPiece all_extensions, 7435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaHeaders* extensions) { 7445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece extension; 7455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece remaining; 7465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringPieceUtils::RemoveWhitespaceContext(&all_extensions); 7475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SplitStringPiece(all_extensions, ';', &extension, &remaining); 7485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (!extension.empty()) { 7495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece key; 7505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece value; 7515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SplitStringPiece(extension, '=', &key, &value); 7525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.empty()) { 7535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Strip quotation marks if they exist. 7545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.empty() && value[0] == '"') 7555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value.remove_prefix(1); 7565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!value.empty() && value[value.length() - 1] == '"') 7575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) value.remove_suffix(1); 7585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions->AppendHeader(key, value); 7615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StringPieceUtils::RemoveWhitespaceContext(&remaining); 7635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) SplitStringPiece(remaining, ';', &extension, &remaining); 7645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 7655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // anonymous namespace 7685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::ProcessChunkExtensions(const char* input, size_t size, 7705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaHeaders* extensions) { 7715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessChunkExtensionsManual(base::StringPiece(input, size), extensions); 7725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 7735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::ProcessHeaderLines() { 7755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeaderLines::size_type content_length_idx = 0; 7765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeaderLines::size_type transfer_encoding_idx = 0; 7775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(!lines_.empty()); 7795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 7805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "******@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**********\n"; 7815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 7825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There is no need to attempt to process headers if no header lines exist. 7845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // There are at least two lines in the message which are not header lines. 7855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // These two non-header lines are the first line of the message, and the 7865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // last line of the message (which is an empty line). 7875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Thus, we test to see if we have more than two lines total before attempting 7885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // to parse any header lines. 7895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lines_.size() > 2) { 7905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* stream_begin = headers_->OriginalHeaderStreamBegin(); 7915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 7925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Then, for the rest of the header data, we parse these into key-value 7935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // pairs. 7945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) FindColonsAndParseIntoKeyValue(); 7955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // At this point, we've parsed all of the headers. Time to look for those 7965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // headers which we require for framing. 7975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HeaderLines::size_type 7985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) header_lines_size = headers_->header_lines_.size(); 7995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) for (HeaderLines::size_type i = 0; i < header_lines_size; ++i) { 8005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const HeaderLineDescription& current_header_line = 8015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->header_lines_[i]; 8025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* key_begin = 8035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (stream_begin + current_header_line.first_char_idx); 8045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* key_end = (stream_begin + current_header_line.key_end_idx); 8055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t key_len = key_end - key_begin; 8065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *key_begin; 8075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 8085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "[" << i << "]: " << std::string(key_begin, key_len) 8095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " c: '" << c << "' key_len: " << key_len; 8105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 8115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If a header begins with either lowercase or uppercase 'c' or 't', then 8125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the header may be one of content-length, connection, content-encoding 8135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // or transfer-encoding. These headers are special, as they change the way 8145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that the message is framed, and so the framer is required to search 8155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for them. 8165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == 'c' || c == 'C') { 8195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((key_len == kContentLengthSize) && 8205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0 == strncasecmp(key_begin, kContentLength, kContentLengthSize)) { 8215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaHeadersEnums::ContentLengthStatus content_length_status = 8225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaHeadersEnums::NO_CONTENT_LENGTH; 8235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t length = 0; 8245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessContentLengthLine(i, &content_length_status, &length); 8255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_length_idx != 0) { // then we've already seen one! 8265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((headers_->content_length_status_ != content_length_status) || 8275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((headers_->content_length_status_ == 8285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaHeadersEnums::VALID_CONTENT_LENGTH) && 8295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) length != headers_->content_length_)) { 8305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::MULTIPLE_CONTENT_LENGTH_KEYS; 8315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 8325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 8335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 8365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_idx = i + 1; 8385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->content_length_status_ = content_length_status; 8395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->content_length_ = length; 8405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_remaining_ = length; 8415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (c == 't' || c == 'T') { 8455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((key_len == kTransferEncodingSize) && 8465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0 == strncasecmp(key_begin, kTransferEncoding, 8475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) kTransferEncodingSize)) { 8485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (transfer_encoding_idx != 0) { 8495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::MULTIPLE_TRANSFER_ENCODING_KEYS; 8505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 8515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 8525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) transfer_encoding_idx = i + 1; 8555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (i == 0 && (key_len == 0 || c == ' ')) { 8575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::INVALID_HEADER_FORMAT; 8585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 8595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 8605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 8615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers_->transfer_encoding_is_chunked_) { 8645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->content_length_ = 0; 8655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH; 8665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_remaining_ = 0; 8675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (transfer_encoding_idx != 0) { 8695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessTransferEncodingLine(transfer_encoding_idx - 1); 8705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 8725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 8735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 8745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::AssignParseStateAfterHeadersHaveBeenParsed() { 8755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // For responses, can't have a body if the request was a HEAD, or if it is 8765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // one of these response-codes. rfc2616 section 4.3 8775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 8785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_request_ || 8795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) !(request_was_head_ || 8805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (headers_->parsed_response_code_ >= 100 && 8815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->parsed_response_code_ < 200) || 8825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (headers_->parsed_response_code_ == 204) || 8835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (headers_->parsed_response_code_ == 304))) { 8845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Then we can have a body. 8855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers_->transfer_encoding_is_chunked_) { 8865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that 8875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if ( Transfer-Encoding: chunked && Content-length: ) 8885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // then Transfer-Encoding: chunked trumps. 8895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is as specified in the spec. 8905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // rfc2616 section 4.4.3 8915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_CHUNK_LENGTH; 8925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 8935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Errors parsing content-length definitely can cause 8945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // protocol errors/warnings 8955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (headers_->content_length_status_) { 8965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we have a content-length, and it is parsed 8975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // properly, there are two options. 8985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 1) zero content, in which case the message is done, and 8995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 2) nonzero content, in which case we have to 9005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // consume the body. 9015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaHeadersEnums::VALID_CONTENT_LENGTH: 9025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers_->content_length_ == 0) { 9035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 9045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_CONTENT; 9065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaHeadersEnums::CONTENT_LENGTH_OVERFLOW: 9095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaHeadersEnums::INVALID_CONTENT_LENGTH: 9105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If there were characters left-over after parsing the 9115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // content length, we should flag an error and stop. 9125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 9135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::UNPARSABLE_CONTENT_LENGTH; 9145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 9155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We can have: no transfer-encoding, no content length, and no 9175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // connection: close... 9185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Unfortunately, this case doesn't seem to be covered in the spec. 9195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We'll assume that the safest thing to do here is what the google 9205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // binaries before 2008 already do, which is to assume that 9215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // everything until the connection is closed is body. 9225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaHeadersEnums::NO_CONTENT_LENGTH: 9235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (is_request_) { 9245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) base::StringPiece method = headers_->request_method(); 9255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // POSTs and PUTs should have a detectable body length. If they 9265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do not we consider it an error. 9275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((method.size() == 4 && 9285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strncmp(method.data(), "POST", 4) == 0) || 9295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (method.size() == 3 && 9305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) strncmp(method.data(), "PUT", 3) == 0)) { 9315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 9325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = 9335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::REQUIRED_BODY_BUT_NO_CONTENT_LENGTH; 9345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 9355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 9385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_UNTIL_CLOSE; 9405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::MAYBE_BODY_BUT_NO_CONTENT_LENGTH; 9415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderWarning(this); 9425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 9445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The COV_NF_... statements here provide hints to the apparatus 9455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which computes coverage reports/ratios that this code is never 9465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // intended to be executed, and should technically be impossible. 9475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // COV_NF_START 9485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 9495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(FATAL) << "Saw a content_length_status: " 9505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << headers_->content_length_status_ << " which is unknown."; 9515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // COV_NF_END 9525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 9565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BalsaFrame::ProcessHeaders(const char* message_start, 9585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t message_length) { 9595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const original_message_start = message_start; 9605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const message_end = message_start + message_length; 9615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* message_current = message_start; 9625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* checkpoint = message_start; 9635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message_length == 0) { 9655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 9665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (message_current < message_end) { 9695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t base_idx = headers_->GetReadableBytesFromHeaderStream(); 9705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 9715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Yes, we could use strchr (assuming null termination), or 9725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // memchr, but as it turns out that is slower than this tight loop 9735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // for the input that we see. 9745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!saw_non_newline_char_) { 9755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) do { 9765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *message_current; 9775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c != '\r' && c != '\n') { 9785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c <= ' ') { 9795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 9805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::NO_REQUEST_LINE_IN_REQUEST; 9815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 9825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 9835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) saw_non_newline_char_ = true; 9855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) checkpoint = message_start = message_current; 9865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto read_real_message; 9875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 9895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++message_current; 9905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } while (message_current < message_end); 9915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // this is necessary to skip 'last_char_was_slash_r' checks 9925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 9935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) read_real_message: 9945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that SSE2 can be enabled on certain piii platforms. 9955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if __SSE2__ 9965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 9975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* const message_end_m16 = message_end - 16; 998116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch __m128i newlines = _mm_set1_epi8('\n'); 9995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (message_current < message_end_m16) { 10005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // What this does (using compiler intrinsics): 10015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 10025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load 16 '\n's into an xmm register 10035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Load 16 bytes of currennt message into an xmm register 10045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Do byte-wise equals on those two xmm registers 10055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Take the first bit of each byte, and put that into the first 10065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 16 bits of a mask 10075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If the mask is zero, no '\n' found. increment by 16 and try again 10085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Else scan forward to find the first set bit. 10095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Increment current by the index of the first set bit 10105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // (ffs returns index of first set bit + 1) 10115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) __m128i msg_bytes = 10125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) _mm_loadu_si128(const_cast<__m128i *>( 10135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) reinterpret_cast<const __m128i *>(message_current))); 1014116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch __m128i newline_cmp = _mm_cmpeq_epi8(msg_bytes, newlines); 10155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) int newline_msk = _mm_movemask_epi8(newline_cmp); 10165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (newline_msk == 0) { 10175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_current += 16; 10185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 10195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_current += (ffs(newline_msk) - 1); 10215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t relative_idx = message_current - message_start; 10225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t message_current_idx = 1 + base_idx + relative_idx; 10235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines_.push_back(std::make_pair(last_slash_n_idx_, 10245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_current_idx)); 10255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lines_.size() == 1) { 10265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->WriteFromFramer(checkpoint, 10275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1 + message_current - checkpoint); 10285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) checkpoint = message_current + 1; 10295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* begin = headers_->OriginalHeaderStreamBegin(); 10305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 10315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "First line " << std::string(begin, lines_[0].second); 10325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "is_request_: " << is_request_; 10335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 10345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessFirstLine(begin, begin + lines_[0].second); 10355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) 10365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto process_lines; 10375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) 10385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 10395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t chars_since_last_slash_n = (message_current_idx - 10415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_idx_); 10425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_idx_ = message_current_idx; 10435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chars_since_last_slash_n > 2) { 10445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // We have a slash-n, but the last slash n was 10455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // more than 2 characters away from this. Thus, we know 10465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // that this cannot be an end-of-header. 10475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++message_current; 10485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 10495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((chars_since_last_slash_n == 1) || 10515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (((message_current > message_start) && 10525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*(message_current - 1) == '\r')) || 10535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (last_char_was_slash_r_))) { 10545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto process_lines; 10555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++message_current; 10575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // __SSE2__ 10605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (message_current < message_end) { 10615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (*message_current != '\n') { 10625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++message_current; 10635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 10645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t relative_idx = message_current - message_start; 10665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t message_current_idx = 1 + base_idx + relative_idx; 10675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) lines_.push_back(std::make_pair(last_slash_n_idx_, 10685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) message_current_idx)); 10695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (lines_.size() == 1) { 10705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->WriteFromFramer(checkpoint, 10715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1 + message_current - checkpoint); 10725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) checkpoint = message_current + 1; 10735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* begin = headers_->OriginalHeaderStreamBegin(); 10745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 10755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "First line " << std::string(begin, lines_[0].second); 10765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "is_request_: " << is_request_; 10775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 10785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessFirstLine(begin, begin + lines_[0].second); 10795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) 10805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto process_lines; 10815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) 10825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 10835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t chars_since_last_slash_n = (message_current_idx - 10855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_idx_); 10865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_slash_n_idx_ = message_current_idx; 10875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chars_since_last_slash_n > 2) { 10885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // false positive. 10895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++message_current; 10905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 10915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((chars_since_last_slash_n == 1) || 10935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (((message_current > message_start) && 10945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (*(message_current - 1) == '\r')) || 10955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (last_char_was_slash_r_))) { 10965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto process_lines; 10975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 10985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++message_current; 10995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 11025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) process_lines: 11035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++message_current; 11045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(message_current >= message_start); 11055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message_current > message_start) { 11065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->WriteFromFramer(checkpoint, message_current - checkpoint); 11075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Check if we have exceeded maximum headers length 11105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Although we check for this limit before and after we call this function 11115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we check it here as well to make sure that in case the visitor changed 11125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the max_header_length_ (for example after processing the first line) 11135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we handle it gracefully. 11145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers_->GetReadableBytesFromHeaderStream() > max_header_length_) { 11155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 11165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::HEADERS_TOO_LONG; 11175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 11185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 11195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Since we know that we won't be writing any more bytes of the header, 11225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // we tell that to the headers object. The headers object may make 11235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // more efficient allocation decisions when this is signaled. 11245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->DoneWritingFromFramer(); 11255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 11265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* readable_ptr = NULL; 11275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t readable_size = 0; 11285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->GetReadablePtrFromHeaderStream(&readable_ptr, &readable_size); 11295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessHeaderInput(readable_ptr, readable_size); 11305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Ok, now that we've written everything into our header buffer, it is 11335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // time to process the header lines (extract proper values for headers 11345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // which are important for framing). 11355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ProcessHeaderLines(); 11365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) { 11375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 11385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) AssignParseStateAfterHeadersHaveBeenParsed(); 11405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) { 11415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 11425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessHeaders(*headers_); 11445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HeaderDone(); 11455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) { 11465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->MessageDone(); 11475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 11495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we've gotten to here, it means that we've consumed all of the 11515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // available input. We need to record whether or not the last character we 11525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // saw was a '\r' so that a subsequent call to ProcessInput correctly finds 11535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // a header framing that is split across the two calls. 11545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_char_was_slash_r_ = (*(message_end - 1) == '\r'); 11555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(message_current >= message_start); 11565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (message_current > message_start) { 11575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->WriteFromFramer(checkpoint, message_current - checkpoint); 11585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bottom: 11605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return message_current - original_message_start; 11615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BalsaFrame::BytesSafeToSplice() const { 11655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (parse_state_) { 11665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CHUNK_DATA: 11675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return chunk_length_remaining_; 11685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_UNTIL_CLOSE: 11695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return std::numeric_limits<size_t>::max(); 11705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CONTENT: 11715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return content_length_remaining_; 11725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 11735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return 0; 11745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 11765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BalsaFrame::BytesSpliced(size_t bytes_spliced) { 11785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (parse_state_) { 11795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CHUNK_DATA: 11805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chunk_length_remaining_ >= bytes_spliced) { 11815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_remaining_ -= bytes_spliced; 11825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chunk_length_remaining_ == 0) { 11835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_CHUNK_TERM; 11845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 11865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 11875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = 11885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT; 11895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto error_exit; 11905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 11915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_UNTIL_CLOSE: 11935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 11945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 11955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CONTENT: 11965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_length_remaining_ >= bytes_spliced) { 11975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_remaining_ -= bytes_spliced; 11985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_length_remaining_ == 0) { 11995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 12005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->MessageDone(); 12015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return; 12035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 12045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = 12055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) BalsaFrameEnums::CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT; 12065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto error_exit; 12075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 12105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::CALLED_BYTES_SPLICED_WHEN_UNSAFE_TO_DO_SO; 12115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto error_exit; 12125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) error_exit: 12155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 12165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleBodyError(this); 12175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 12185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// You may note that the state-machine contained within this function has both 12205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// switch and goto labels for nearly the same thing. For instance, the 12215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// following two labels refer to the same code block: 12225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// label_reading_chunk_data: 12235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// case BalsaFrameEnums::READING_CHUNK_DATA: 12245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The 'case' statement is required for the switch statement which occurs when 12255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ProcessInput is invoked. The goto label is required as the state-machine 12265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// does not use a computed goto in any subsequent operations. 12275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 12285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Since several states exit the state machine for various reasons, there is 12295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// also one label at the bottom of the function. When it is appropriate to 12305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// return from the function, that part of the state machine instead issues a 12315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// goto bottom; This results in less code duplication, and makes debugging 12325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// easier (as you can add a statement to a section of code which is guaranteed 12335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// to be invoked when the function is exiting. 12345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)size_t BalsaFrame::ProcessInput(const char* input, size_t size) { 12355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* current = input; 12365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* on_entry = current; 12375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* end = current + size; 12385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 12395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "\n==============" 12405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << BalsaFrameEnums::ParseStateToString(parse_state_) 12415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "===============\n"; 12425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 12435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) DCHECK(headers_ != NULL); 12455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (headers_ == NULL) return 0; 12465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parse_state_ == BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE) { 12485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t header_length = headers_->GetReadableBytesFromHeaderStream(); 12495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Yes, we still have to check this here as the user can change the 12505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // max_header_length amount! 12515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Also it is possible that we have reached the maximum allowed header size, 12525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // and we have more to consume (remember we are still inside 12535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // READING_HEADER_AND_FIRSTLINE) in which case we directly declare an error. 12545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header_length > max_header_length_ || 12555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (header_length == max_header_length_ && size > 0)) { 12565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 12575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::HEADERS_TOO_LONG; 12585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 12595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 12605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t bytes_to_process = max_header_length_ - header_length; 12625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bytes_to_process > size) { 12635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bytes_to_process = size; 12645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current += ProcessHeaders(input, bytes_to_process); 12665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we are still reading headers check if we have crossed the headers 12675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // limit. Note that we check for >= as opposed to >. This is because if 12685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // header_length_after equals max_header_length_ and we are still in the 12695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // parse_state_ BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE we know for 12705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // sure that the headers limit will be crossed later on 12715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (parse_state_ == BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE) { 12725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that headers_ is valid only if we are still reading headers. 12735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t header_length_after = 12745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) headers_->GetReadableBytesFromHeaderStream(); 12755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (header_length_after >= max_header_length_) { 12765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 12775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::HEADERS_TOO_LONG; 12785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleHeaderError(this); 12795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 12825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ || 12835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ == BalsaFrameEnums::PARSE_ERROR) { 12845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Can do nothing more 'till we're reset. 12855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 12865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 12875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 12885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < end) { 12895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) switch (parse_state_) { 12905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_reading_chunk_length: 12915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CHUNK_LENGTH: 12925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // In this state we read the chunk length. 12935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that once we hit a character which is not in: 12945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // [0-9;A-Fa-f\n], we transition to a different state. 12955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 12965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 12975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we used strtol, etc, we'd have to buffer this line. 12985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // This is more annoying than simply doing the conversion 12995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // here. This code accounts for overflow. 13005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const signed char buf[] = { 13015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // %0 %1 %2 %3 %4 %5 %6 %7 %8 \t \n %b %c \r %e %f 13025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1, 13035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // %10 %11 %12 %13 %14 %15 %16 %17 %18 %19 %1a %1b %1c %1d %1e %1f 13045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ' ' %21 %22 %23 %24 %25 %26 %27 %28 %29 %2a %2b %2c %2d %2e %2f 13065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // %30 %31 %32 %33 %34 %35 %36 %37 %38 %39 %3a ';' %3c %3d %3e %3f 13085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -2, -1, -1, -1, -1, 13095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // %40 'A' 'B' 'C' 'D' 'E' 'F' %47 %48 %49 %4a %4b %4c %4d %4e %4f 13105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // %50 %51 %52 %53 %54 %55 %56 %57 %58 %59 %5a %5b %5c %5d %5e %5f 13125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // %60 'a' 'b' 'c' 'd' 'e' 'f' %67 %68 %69 %6a %6b %6c %6d %6e %6f 13145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // %70 %71 %72 %73 %74 %75 %76 %77 %78 %79 %7a %7b %7c %7d %7e %7f 13165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 13175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) }; 13185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // valid cases: 13195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123\n" // -> 09123 13205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123\r\n" // -> 09123 13215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123 \n" // -> 09123 13225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123 \r\n" // -> 09123 13235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123 12312\n" // -> 09123 13245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123 12312\r\n" // -> 09123 13255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123; foo=bar\n" // -> 09123 13265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "09123; foo=bar\r\n" // -> 09123 13275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "FFFFFFFFFFFFFFFF\r\n" // -> FFFFFFFFFFFFFFFF 13285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "FFFFFFFFFFFFFFFF 22\r\n" // -> FFFFFFFFFFFFFFFF 13295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // invalid cases: 13305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "[ \t]+[^\n]*\n" 13315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "FFFFFFFFFFFFFFFFF\r\n" (would overflow) 13325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "\r\n" 13335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // "\n" 13345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < end) { 13355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *current; 13365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 13375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const signed char addition = buf[static_cast<int>(c)]; 13385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (addition >= 0) { 13395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_character_extracted_ = true; 13405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t length_x_16 = chunk_length_remaining_ * 16; 13415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t kMaxDiv16 = std::numeric_limits<size_t>::max() / 16; 13425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if ((chunk_length_remaining_ > kMaxDiv16) || 13435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ((std::numeric_limits<size_t>::max() - length_x_16) < 13445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static_cast<size_t>(addition))) { 13455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // overflow -- asked for a chunk-length greater than 2^64 - 1!! 13465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 13475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::CHUNK_LENGTH_OVERFLOW; 13485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 13495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleChunkingError(this); 13505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 13515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_remaining_ = length_x_16 + addition; 13535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 13545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!chunk_length_character_extracted_ || addition == -1) { 13575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ^[0-9;A-Fa-f][ \t\n] -- was not matched, either because no 13585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // characters were converted, or an unexpected character was 13595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // seen. 13605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::PARSE_ERROR; 13615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) last_error_ = BalsaFrameEnums::INVALID_CHUNK_LENGTH; 13625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 13635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->HandleChunkingError(this); 13645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 13655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) --current; 13685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_CHUNK_EXTENSION; 13695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessChunkLength(chunk_length_remaining_); 13705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto label_reading_chunk_extension; 13715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 13745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // case BalsaFrameEnums::READING_CHUNK_LENGTH 13755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_reading_chunk_extension: 13775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CHUNK_EXTENSION: 13785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 13795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(phython): Convert this scanning to be 16 bytes at a time if 13805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // there is data to be read. 13815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* extensions_start = current; 13825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t extensions_length = 0; 13835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < end) { 13845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *current; 13855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '\r' || c == '\n') { 13865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions_length = 13875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (extensions_start == current) ? 13885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 0 : 13895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current - extensions_start - 1; 13905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 13915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 13925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 13935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '\n') { 13945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_character_extracted_ = false; 13955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessChunkExtensions( 13965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions_start, extensions_length); 13975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chunk_length_remaining_ != 0) { 13985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_CHUNK_DATA; 13995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto label_reading_chunk_data; 14005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) HeaderFramingFound('\n'); 14025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_LAST_CHUNK_TERM; 14035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto label_reading_last_chunk_term; 14045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessChunkExtensions( 14075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) extensions_start, extensions_length); 14085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 14115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // case BalsaFrameEnums::READING_CHUNK_EXTENSION 14125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_reading_chunk_data: 14145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CHUNK_DATA: 14155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < end) { 14165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chunk_length_remaining_ == 0) { 14175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; 14185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // read in the chunk 14205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t bytes_remaining = end - current; 14215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) size_t consumed_bytes = (chunk_length_remaining_ < bytes_remaining) ? 14225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_remaining_ : bytes_remaining; 14235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char* tmp_current = current + consumed_bytes; 14245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, tmp_current - on_entry); 14255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyData(current, consumed_bytes); 14265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) on_entry = current = tmp_current; 14275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) chunk_length_remaining_ -= consumed_bytes; 14285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (chunk_length_remaining_ == 0) { 14305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_CHUNK_TERM; 14315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto label_reading_chunk_term; 14325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 14345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // case BalsaFrameEnums::READING_CHUNK_DATA 14355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_reading_chunk_term: 14375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CHUNK_TERM: 14385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < end) { 14395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *current; 14405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 14415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (c == '\n') { 14435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_CHUNK_LENGTH; 14445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto label_reading_chunk_length; 14455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 14485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // case BalsaFrameEnums::READING_CHUNK_TERM 14495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_reading_last_chunk_term: 14515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_LAST_CHUNK_TERM: 14525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < end) { 14535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *current; 14545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!HeaderFramingFound(c)) { 14565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If not, however, since the spec only suggests that the 14575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // client SHOULD indicate the presence of trailers, we get to 14585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // *test* that they did or didn't. 14595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If all of the bytes we've seen since: 14605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // OPTIONAL_WS 0 OPTIONAL_STUFF CRLF 14615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // are either '\r', or '\n', then we can assume that we don't yet 14625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // know if we need to parse headers, or if the next byte will make 14635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // the HeaderFramingFound condition (above) true. 14645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HeaderFramingMayBeFound()) { 14655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If true, then we have seen only characters '\r' or '\n'. 14665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 14675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Lets try again! There is no state change here. 14695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) continue; 14705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 14715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If (!HeaderFramingMayBeFound()), then we know that we must be 14725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reading the first non CRLF character of a trailer. 14735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::READING_TRAILER; 14745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 14755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) on_entry = current; 14765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto label_reading_trailer; 14775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 14795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // If we've found a "\r\n\r\n", then the message 14805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // is done. 14815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 14825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 14835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 14845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->MessageDone(); 14855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 14865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; // from while loop 14885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 14895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(on_entry, current - on_entry); 14905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // case BalsaFrameEnums::READING_LAST_CHUNK_TERM 14915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 14925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) label_reading_trailer: 14935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_TRAILER: 14945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (current < end) { 14955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const char c = *current; 14965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ++current; 14975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(fenix): If we ever care about trailers as part of framing, 14985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // deal with them here (see below for part of the 'solution') 14995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // if (LineFramingFound(c)) { 15005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trailer_lines_.push_back(make_pair(start_of_line_, 15015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // trailer_length_ - 1)); 15025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // start_of_line_ = trailer_length_; 15035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // } 15045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (HeaderFramingFound(c)) { 15055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ProcessTrailers(visitor_, &trailers_); 15065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 15075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessTrailerInput(on_entry, current - on_entry); 15085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->MessageDone(); 15095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; 15105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessTrailerInput(on_entry, current - on_entry); 15135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) break; // case BalsaFrameEnums::READING_TRAILER 15145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note that there is no label: 15165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // 'label_reading_until_close' 15175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // here. This is because the state-machine exists immediately after 15185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // reading the headers instead of transitioning here (as it would 15195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // do if it was consuming all the data it could, all the time). 15205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_UNTIL_CLOSE: 15215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) { 15225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t bytes_remaining = end - current; 15235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (bytes_remaining > 0) { 15245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(current, bytes_remaining); 15255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyData(current, bytes_remaining); 15265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current += bytes_remaining; 15275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // case BalsaFrameEnums::READING_UNTIL_CLOSE 15305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // label_reading_content: 15325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) case BalsaFrameEnums::READING_CONTENT: 15335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 15345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "ReadingContent: " << content_length_remaining_; 15355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 15365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while (content_length_remaining_ && current < end) { 15375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // read in the content 15385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t bytes_remaining = end - current; 15395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const size_t consumed_bytes = 15405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) (content_length_remaining_ < bytes_remaining) ? 15415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_remaining_ : bytes_remaining; 15425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyInput(current, consumed_bytes); 15435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->ProcessBodyData(current, consumed_bytes); 15445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) current += consumed_bytes; 15455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) content_length_remaining_ -= consumed_bytes; 15465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (content_length_remaining_ == 0) { 15485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ; 15495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) visitor_->MessageDone(); 15505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) goto bottom; // case BalsaFrameEnums::READING_CONTENT 15525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) default: 15545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // The state-machine should never be in a state that isn't handled 15555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // above. This is a glaring logic error, and we should do something 15565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // drastic to ensure that this gets looked-at and fixed. 15575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(FATAL) << "Unknown state: " << parse_state_ // COV_NF_LINE 15585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " memory corruption?!"; // COV_NF_LINE 15595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bottom: 15625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if DEBUGFRAMER 15635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n" 15645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << std::string(input, current) 15655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "\n$$$$$$$$$$$$$$" 15665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << BalsaFrameEnums::ParseStateToString(parse_state_) 15675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << "$$$$$$$$$$$$$$$" 15685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) << " consumed: " << (current - input); 15695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (Error()) { 15705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) LOG(INFO) << BalsaFrameEnums::ErrorCodeToString(ErrorCode()); 15715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 15725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // DEBUGFRAMER 15735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return current - input; 15745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} 15755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 15765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 1577