summaryrefslogtreecommitdiffstats
path: root/net/tools/flip_server
diff options
context:
space:
mode:
authorrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-29 15:27:44 +0000
committerrch@chromium.org <rch@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-09-29 15:27:44 +0000
commit6c7e65208cedc0ff790738a67794474c679ee578 (patch)
tree71ac7941a02e76e13705e75e712679286931326a /net/tools/flip_server
parent29239893bfafc535339be2adf7845a5010213a51 (diff)
downloadchromium_src-6c7e65208cedc0ff790738a67794474c679ee578.zip
chromium_src-6c7e65208cedc0ff790738a67794474c679ee578.tar.gz
chromium_src-6c7e65208cedc0ff790738a67794474c679ee578.tar.bz2
Break out balsa and epoll_server from net/tools/flip_server.
balsa is an HTTP headers/framing abstraction used by code in net/tools/flip_server and net/tools/quic. epoll_server is a event-driven server abstraction based on (as the name suggested) epoll. It is also used by code in net/tools/flip_server and net/tools/quic. Since these are both shared across different layers, it makes sense to split them into different directories. Review URL: https://codereview.chromium.org/25085002 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@225890 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/tools/flip_server')
-rw-r--r--net/tools/flip_server/acceptor_thread.h2
-rw-r--r--net/tools/flip_server/balsa_enums.h111
-rw-r--r--net/tools/flip_server/balsa_frame.cc1597
-rw-r--r--net/tools/flip_server/balsa_frame.h265
-rw-r--r--net/tools/flip_server/balsa_frame_test.cc599
-rw-r--r--net/tools/flip_server/balsa_headers.cc965
-rw-r--r--net/tools/flip_server/balsa_headers.h1138
-rw-r--r--net/tools/flip_server/balsa_headers_test.cc392
-rw-r--r--net/tools/flip_server/balsa_headers_token_utils.cc142
-rw-r--r--net/tools/flip_server/balsa_headers_token_utils.h61
-rw-r--r--net/tools/flip_server/balsa_visitor_interface.h180
-rw-r--r--net/tools/flip_server/buffer_interface.h121
-rw-r--r--net/tools/flip_server/epoll_server.cc820
-rw-r--r--net/tools/flip_server/epoll_server.h1054
-rw-r--r--net/tools/flip_server/flip_in_mem_edsm_server.cc3
-rw-r--r--net/tools/flip_server/http_interface.cc2
-rw-r--r--net/tools/flip_server/http_interface.h4
-rw-r--r--net/tools/flip_server/http_interface_test.cc6
-rw-r--r--net/tools/flip_server/http_message_constants.h17
-rw-r--r--net/tools/flip_server/mem_cache.cc4
-rw-r--r--net/tools/flip_server/mem_cache.h4
-rw-r--r--net/tools/flip_server/mem_cache_test.cc2
-rw-r--r--net/tools/flip_server/noop_balsa_visitor.h60
-rw-r--r--net/tools/flip_server/output_ordering.h2
-rw-r--r--net/tools/flip_server/ring_buffer.h2
-rw-r--r--net/tools/flip_server/simple_buffer.cc208
-rw-r--r--net/tools/flip_server/simple_buffer.h92
-rw-r--r--net/tools/flip_server/sm_connection.h2
-rw-r--r--net/tools/flip_server/sm_interface.h2
-rw-r--r--net/tools/flip_server/spdy_interface.h4
-rw-r--r--net/tools/flip_server/spdy_interface_test.cc4
-rw-r--r--net/tools/flip_server/split.cc72
-rw-r--r--net/tools/flip_server/split.h23
-rw-r--r--net/tools/flip_server/streamer_interface.cc2
-rw-r--r--net/tools/flip_server/streamer_interface.h4
-rw-r--r--net/tools/flip_server/string_piece_utils.h83
36 files changed, 24 insertions, 8025 deletions
diff --git a/net/tools/flip_server/acceptor_thread.h b/net/tools/flip_server/acceptor_thread.h
index f967fac..7c758d9 100644
--- a/net/tools/flip_server/acceptor_thread.h
+++ b/net/tools/flip_server/acceptor_thread.h
@@ -11,7 +11,7 @@
#include "base/compiler_specific.h"
#include "base/threading/simple_thread.h"
-#include "net/tools/flip_server/epoll_server.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/flip_server/sm_interface.h"
#include "openssl/ssl.h"
diff --git a/net/tools/flip_server/balsa_enums.h b/net/tools/flip_server/balsa_enums.h
deleted file mode 100644
index 4273ee4..0000000
--- a/net/tools/flip_server/balsa_enums.h
+++ /dev/null
@@ -1,111 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_BALSA_ENUMS_H_
-#define NET_TOOLS_FLIP_SERVER_BALSA_ENUMS_H_
-
-namespace net {
-
-struct BalsaFrameEnums {
- enum ParseState {
- PARSE_ERROR,
- READING_HEADER_AND_FIRSTLINE,
- READING_CHUNK_LENGTH,
- READING_CHUNK_EXTENSION,
- READING_CHUNK_DATA,
- READING_CHUNK_TERM,
- READING_LAST_CHUNK_TERM,
- READING_TRAILER,
- READING_UNTIL_CLOSE,
- READING_CONTENT,
- MESSAGE_FULLY_READ,
- NUM_STATES,
- };
-
- enum ErrorCode {
- NO_ERROR = 0, // A sentinel value for convenience, none of the callbacks
- // should ever see this error code.
- // Header parsing errors
- // Note that adding one to many of the REQUEST errors yields the
- // appropriate RESPONSE error.
- // Particularly, when parsing the first line of a request or response,
- // there are three sequences of non-whitespace regardless of whether or
- // not it is a request or response. These are listed below, in order.
- //
- // firstline_a firstline_b firstline_c
- // REQ: method request_uri version
- // RESP: version statuscode reason
- //
- // As you can see, the first token is the 'method' field for a request,
- // and 'version' field for a response. We call the first non whitespace
- // token firstline_a, the second firstline_b, and the third token
- // followed by [^\r\n]*) firstline_c.
- //
- // This organization is important, as it lets us determine the error code
- // to use without a branch based on is_response. Instead, we simply add
- // is_response to the response error code-- If is_response is true, then
- // we'll get the response error code, thanks to the fact that the error
- // code numbers are organized to ensure that response error codes always
- // precede request error codes.
- // | Triggered
- // | while processing
- // | this NONWS
- // | sequence...
- NO_STATUS_LINE_IN_RESPONSE, // |
- NO_REQUEST_LINE_IN_REQUEST, // |
- FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION, // | firstline_a
- FAILED_TO_FIND_WS_AFTER_REQUEST_METHOD, // | firstline_a
- FAILED_TO_FIND_WS_AFTER_RESPONSE_STATUSCODE, // | firstline_b
- FAILED_TO_FIND_WS_AFTER_REQUEST_REQUEST_URI, // | firstline_b
- FAILED_TO_FIND_NL_AFTER_RESPONSE_REASON_PHRASE, // | firstline_c
- FAILED_TO_FIND_NL_AFTER_REQUEST_HTTP_VERSION, // | firstline_c
-
- FAILED_CONVERTING_STATUS_CODE_TO_INT,
- REQUEST_URI_TOO_LONG, // Request URI greater than kMaxUrlLen.
-
- HEADERS_TOO_LONG,
- UNPARSABLE_CONTENT_LENGTH,
- // Warning: there may be a body but there was no content-length/chunked
- // encoding
- MAYBE_BODY_BUT_NO_CONTENT_LENGTH,
-
- // This is used if a body is required for a request.
- REQUIRED_BODY_BUT_NO_CONTENT_LENGTH,
-
- HEADER_MISSING_COLON,
-
- // Chunking errors
- INVALID_CHUNK_LENGTH,
- CHUNK_LENGTH_OVERFLOW,
-
- // Other errors.
- CALLED_BYTES_SPLICED_WHEN_UNSAFE_TO_DO_SO,
- CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT,
- MULTIPLE_CONTENT_LENGTH_KEYS,
- MULTIPLE_TRANSFER_ENCODING_KEYS,
- UNKNOWN_TRANSFER_ENCODING,
- INVALID_HEADER_FORMAT,
-
- // A detected internal inconsistency was found.
- INTERNAL_LOGIC_ERROR,
-
- NUM_ERROR_CODES
- };
- static const char* ParseStateToString(ParseState error_code);
- static const char* ErrorCodeToString(ErrorCode error_code);
-};
-
-struct BalsaHeadersEnums {
- enum ContentLengthStatus {
- INVALID_CONTENT_LENGTH,
- CONTENT_LENGTH_OVERFLOW,
- NO_CONTENT_LENGTH,
- VALID_CONTENT_LENGTH,
- };
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_BALSA_ENUMS_H_
-
diff --git a/net/tools/flip_server/balsa_frame.cc b/net/tools/flip_server/balsa_frame.cc
deleted file mode 100644
index dead665..0000000
--- a/net/tools/flip_server/balsa_frame.cc
+++ /dev/null
@@ -1,1597 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/balsa_frame.h"
-
-#include <assert.h>
-#if __SSE2__
-#include <emmintrin.h>
-#endif // __SSE2__
-#include <strings.h>
-
-#include <limits>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/port.h"
-#include "base/strings/string_piece.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "net/tools/flip_server/balsa_headers.h"
-#include "net/tools/flip_server/balsa_visitor_interface.h"
-#include "net/tools/flip_server/buffer_interface.h"
-#include "net/tools/flip_server/simple_buffer.h"
-#include "net/tools/flip_server/split.h"
-#include "net/tools/flip_server/string_piece_utils.h"
-
-namespace net {
-
-// Constants holding some header names for headers which can affect the way the
-// HTTP message is framed, and so must be processed specially:
-static const char kContentLength[] = "content-length";
-static const size_t kContentLengthSize = sizeof(kContentLength) - 1;
-static const char kTransferEncoding[] = "transfer-encoding";
-static const size_t kTransferEncodingSize = sizeof(kTransferEncoding) - 1;
-
-BalsaFrame::BalsaFrame()
- : last_char_was_slash_r_(false),
- saw_non_newline_char_(false),
- start_was_space_(true),
- chunk_length_character_extracted_(false),
- is_request_(true),
- request_was_head_(false),
- max_header_length_(16 * 1024),
- max_request_uri_length_(2048),
- visitor_(&do_nothing_visitor_),
- chunk_length_remaining_(0),
- content_length_remaining_(0),
- last_slash_n_loc_(NULL),
- last_recorded_slash_n_loc_(NULL),
- last_slash_n_idx_(0),
- term_chars_(0),
- parse_state_(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE),
- last_error_(BalsaFrameEnums::NO_ERROR),
- headers_(NULL) {
-}
-
-BalsaFrame::~BalsaFrame() {}
-
-void BalsaFrame::Reset() {
- last_char_was_slash_r_ = false;
- saw_non_newline_char_ = false;
- start_was_space_ = true;
- chunk_length_character_extracted_ = false;
- // is_request_ = true; // not reset between messages.
- // request_was_head_ = false; // not reset between messages.
- // max_header_length_ = 4096; // not reset between messages.
- // max_request_uri_length_ = 2048; // not reset between messages.
- // visitor_ = &do_nothing_visitor_; // not reset between messages.
- chunk_length_remaining_ = 0;
- content_length_remaining_ = 0;
- last_slash_n_loc_ = NULL;
- last_recorded_slash_n_loc_ = NULL;
- last_slash_n_idx_ = 0;
- term_chars_ = 0;
- parse_state_ = BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE;
- last_error_ = BalsaFrameEnums::NO_ERROR;
- lines_.clear();
- if (headers_ != NULL) {
- headers_->Clear();
- }
-}
-
-const char* BalsaFrameEnums::ParseStateToString(
- BalsaFrameEnums::ParseState error_code) {
- switch (error_code) {
- case PARSE_ERROR:
- return "PARSE_ERROR";
- case READING_HEADER_AND_FIRSTLINE:
- return "READING_HEADER_AND_FIRSTLINE";
- case READING_CHUNK_LENGTH:
- return "READING_CHUNK_LENGTH";
- case READING_CHUNK_EXTENSION:
- return "READING_CHUNK_EXTENSION";
- case READING_CHUNK_DATA:
- return "READING_CHUNK_DATA";
- case READING_CHUNK_TERM:
- return "READING_CHUNK_TERM";
- case READING_LAST_CHUNK_TERM:
- return "READING_LAST_CHUNK_TERM";
- case READING_TRAILER:
- return "READING_TRAILER";
- case READING_UNTIL_CLOSE:
- return "READING_UNTIL_CLOSE";
- case READING_CONTENT:
- return "READING_CONTENT";
- case MESSAGE_FULLY_READ:
- return "MESSAGE_FULLY_READ";
- case NUM_STATES:
- return "UNKNOWN_STATE";
- }
- return "UNKNOWN_STATE";
-}
-
-const char* BalsaFrameEnums::ErrorCodeToString(
- BalsaFrameEnums::ErrorCode error_code) {
- switch (error_code) {
- case NO_ERROR:
- return "NO_ERROR";
- case NO_STATUS_LINE_IN_RESPONSE:
- return "NO_STATUS_LINE_IN_RESPONSE";
- case NO_REQUEST_LINE_IN_REQUEST:
- return "NO_REQUEST_LINE_IN_REQUEST";
- case FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION:
- return "FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION";
- case FAILED_TO_FIND_WS_AFTER_REQUEST_METHOD:
- return "FAILED_TO_FIND_WS_AFTER_REQUEST_METHOD";
- case FAILED_TO_FIND_WS_AFTER_RESPONSE_STATUSCODE:
- return "FAILED_TO_FIND_WS_AFTER_RESPONSE_STATUSCODE";
- case FAILED_TO_FIND_WS_AFTER_REQUEST_REQUEST_URI:
- return "FAILED_TO_FIND_WS_AFTER_REQUEST_REQUEST_URI";
- case FAILED_TO_FIND_NL_AFTER_RESPONSE_REASON_PHRASE:
- return "FAILED_TO_FIND_NL_AFTER_RESPONSE_REASON_PHRASE";
- case FAILED_TO_FIND_NL_AFTER_REQUEST_HTTP_VERSION:
- return "FAILED_TO_FIND_NL_AFTER_REQUEST_HTTP_VERSION";
- case FAILED_CONVERTING_STATUS_CODE_TO_INT:
- return "FAILED_CONVERTING_STATUS_CODE_TO_INT";
- case REQUEST_URI_TOO_LONG:
- return "REQUEST_URI_TOO_LONG";
- case HEADERS_TOO_LONG:
- return "HEADERS_TOO_LONG";
- case UNPARSABLE_CONTENT_LENGTH:
- return "UNPARSABLE_CONTENT_LENGTH";
- case MAYBE_BODY_BUT_NO_CONTENT_LENGTH:
- return "MAYBE_BODY_BUT_NO_CONTENT_LENGTH";
- case REQUIRED_BODY_BUT_NO_CONTENT_LENGTH:
- return "REQUIRED_BODY_BUT_NO_CONTENT_LENGTH";
- case HEADER_MISSING_COLON:
- return "HEADER_MISSING_COLON";
- case INVALID_CHUNK_LENGTH:
- return "INVALID_CHUNK_LENGTH";
- case CHUNK_LENGTH_OVERFLOW:
- return "CHUNK_LENGTH_OVERFLOW";
- case CALLED_BYTES_SPLICED_WHEN_UNSAFE_TO_DO_SO:
- return "CALLED_BYTES_SPLICED_WHEN_UNSAFE_TO_DO_SO";
- case CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT:
- return "CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT";
- case MULTIPLE_CONTENT_LENGTH_KEYS:
- return "MULTIPLE_CONTENT_LENGTH_KEYS";
- case MULTIPLE_TRANSFER_ENCODING_KEYS:
- return "MULTIPLE_TRANSFER_ENCODING_KEYS";
- case UNKNOWN_TRANSFER_ENCODING:
- return "UNKNOWN_TRANSFER_ENCODING";
- case INVALID_HEADER_FORMAT:
- return "INVALID_HEADER_FORMAT";
- case INTERNAL_LOGIC_ERROR:
- return "INTERNAL_LOGIC_ERROR";
- case NUM_ERROR_CODES:
- return "UNKNOWN_ERROR";
- }
- return "UNKNOWN_ERROR";
-}
-
-// Summary:
-// Parses the first line of either a request or response.
-// Note that in the case of a detected warning, error_code will be set
-// but the function will not return false.
-// Exactly zero or one warning or error (but not both) may be detected
-// by this function.
-// Note that this function will not write the data of the first-line
-// into the header's buffer (that should already have been done elsewhere).
-//
-// Pre-conditions:
-// begin != end
-// *begin should be a character which is > ' '. This implies that there
-// is at least one non-whitespace characters between [begin, end).
-// headers is a valid pointer to a BalsaHeaders class.
-// error_code is a valid pointer to a BalsaFrameEnums::ErrorCode value.
-// Entire first line must exist between [begin, end)
-// Exactly zero or one newlines -may- exist between [begin, end)
-// [begin, end) should exist in the header's buffer.
-//
-// Side-effects:
-// headers will be modified
-// error_code may be modified if either a warning or error is detected
-//
-// Returns:
-// True if no error (as opposed to warning) is detected.
-// False if an error (as opposed to warning) is detected.
-
-//
-// If there is indeed non-whitespace in the line, then the following
-// will take care of this for you:
-// while (*begin <= ' ') ++begin;
-// ProcessFirstLine(begin, end, is_request, &headers, &error_code);
-//
-bool ParseHTTPFirstLine(const char* begin,
- const char* end,
- bool is_request,
- size_t max_request_uri_length,
- BalsaHeaders* headers,
- BalsaFrameEnums::ErrorCode* error_code) {
- const char* current = begin;
- // HTTP firstlines all have the following structure:
- // LWS NONWS LWS NONWS LWS NONWS NOTCRLF CRLF
- // [\t \r\n]+ [^\t ]+ [\t ]+ [^\t ]+ [\t ]+ [^\t ]+ [^\r\n]+ "\r\n"
- // ws1 nws1 ws2 nws2 ws3 nws3 ws4
- // | [-------) [-------) [----------------)
- // REQ: method request_uri version
- // RESP: version statuscode reason
- //
- // The first NONWS->LWS component we'll call firstline_a.
- // The second firstline_b, and the third firstline_c.
- //
- // firstline_a goes from nws1 to (but not including) ws2
- // firstline_b goes from nws2 to (but not including) ws3
- // firstline_c goes from nws3 to (but not including) ws4
- //
- // In the code:
- // ws1 == whitespace_1_idx_
- // nws1 == non_whitespace_1_idx_
- // ws2 == whitespace_2_idx_
- // nws2 == non_whitespace_2_idx_
- // ws3 == whitespace_3_idx_
- // nws3 == non_whitespace_3_idx_
- // ws4 == whitespace_4_idx_
-
- // Kill all whitespace (including '\r\n') at the end of the line.
- --end;
- if (*end != '\n') {
- *error_code = BalsaFrameEnums::INTERNAL_LOGIC_ERROR;
- LOG(DFATAL) << "INTERNAL_LOGIC_ERROR Headers: \n"
- << headers->OriginalHeadersForDebugging();
- return false;
- }
- while (begin < end && *end <= ' ') {
- --end;
- }
- DCHECK(*end != '\n');
- if (*end == '\n') {
- *error_code = BalsaFrameEnums::INTERNAL_LOGIC_ERROR;
- LOG(DFATAL) << "INTERNAL_LOGIC_ERROR Headers: \n"
- << headers->OriginalHeadersForDebugging();
- return false;
- }
- ++end;
-
- // The two following statements should not be possible.
- if (end == begin) {
- *error_code = BalsaFrameEnums::INTERNAL_LOGIC_ERROR;
- LOG(DFATAL) << "INTERNAL_LOGIC_ERROR Headers: \n"
- << headers->OriginalHeadersForDebugging();
- return false;
- }
-
- // whitespace_1_idx_
- headers->whitespace_1_idx_ = current - begin;
- // This loop is commented out as it is never used in current code. This is
- // true only because we don't begin parsing the headers at all until we've
- // encountered a non whitespace character at the beginning of the stream, at
- // which point we begin our demarcation of header-start. If we did -not- do
- // this (for instance, only looked for [\r\n] instead of (< ' ')), this loop
- // would be necessary for the proper functioning of this parsing.
- // This is left here as this function may (in the future) be refactored out
- // of the BalsaFrame class so that it may be shared between code in
- // BalsaFrame and BalsaHeaders (where it would be used in some variant of the
- // set_first_line() function (at which point it would be necessary).
-#if 0
- while (*current <= ' ') {
- ++current;
- }
-#endif
- // non_whitespace_1_idx_
- headers->non_whitespace_1_idx_ = current - begin;
- do {
- // The first time through, we're guaranteed that the current character
- // won't be a whitespace (else the loop above wouldn't have terminated).
- // That implies that we're guaranteed to get at least one non-whitespace
- // character if we get into this loop at all.
- ++current;
- if (current == end) {
- headers->whitespace_2_idx_ = current - begin;
- headers->non_whitespace_2_idx_ = current - begin;
- headers->whitespace_3_idx_ = current - begin;
- headers->non_whitespace_3_idx_ = current - begin;
- headers->whitespace_4_idx_ = current - begin;
- // FAILED_TO_FIND_WS_AFTER_REQUEST_METHOD for request
- // FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION for response
- *error_code =
- static_cast<BalsaFrameEnums::ErrorCode>(
- BalsaFrameEnums::FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION +
- is_request);
- if (!is_request) { // FAILED_TO_FIND_WS_AFTER_RESPONSE_VERSION
- return false;
- }
- goto output_exhausted;
- }
- } while (*current > ' ');
- // whitespace_2_idx_
- headers->whitespace_2_idx_ = current - begin;
- do {
- ++current;
- // Note that due to the loop which consumes all of the whitespace
- // at the end of the line, current can never == end while in this function.
- } while (*current <= ' ');
- // non_whitespace_2_idx_
- headers->non_whitespace_2_idx_ = current - begin;
- do {
- ++current;
- if (current == end) {
- headers->whitespace_3_idx_ = current - begin;
- headers->non_whitespace_3_idx_ = current - begin;
- headers->whitespace_4_idx_ = current - begin;
- // FAILED_TO_FIND_START_OF_REQUEST_REQUEST_URI for request
- // FAILED_TO_FIND_START_OF_RESPONSE_STATUSCODE for response
- *error_code =
- static_cast<BalsaFrameEnums::ErrorCode>(
- BalsaFrameEnums::FAILED_TO_FIND_WS_AFTER_RESPONSE_STATUSCODE
- + is_request);
- goto output_exhausted;
- }
- } while (*current > ' ');
- // whitespace_3_idx_
- headers->whitespace_3_idx_ = current - begin;
- do {
- ++current;
- // Note that due to the loop which consumes all of the whitespace
- // at the end of the line, current can never == end while in this function.
- } while (*current <= ' ');
- // non_whitespace_3_idx_
- headers->non_whitespace_3_idx_ = current - begin;
- headers->whitespace_4_idx_ = end - begin;
-
- output_exhausted:
- // Note that we don't fail the parse immediately when parsing of the
- // firstline fails. Depending on the protocol type, we may want to accept
- // a firstline with only one or two elements, e.g., for HTTP/0.9:
- // GET\r\n
- // or
- // GET /\r\n
- // should be parsed without issue (though the visitor should know that
- // parsing the entire line was not exactly as it should be).
- //
- // Eventually, these errors may be removed alltogether, as the visitor can
- // detect them on its own by examining the size of the various fields.
- // headers->set_first_line(non_whitespace_1_idx_, current);
-
- if (is_request) {
- if ((headers->whitespace_3_idx_ - headers->non_whitespace_2_idx_) >
- max_request_uri_length) {
- // For requests, we need at least the method. We could assume that a
- // blank URI means "/". If version isn't stated, it should be assumed
- // to be HTTP/0.9 by the visitor.
- *error_code = BalsaFrameEnums::REQUEST_URI_TOO_LONG;
- return false;
- }
- } else {
- headers->parsed_response_code_ = 0;
- {
- const char* parsed_response_code_current =
- begin + headers->non_whitespace_2_idx_;
- const char* parsed_response_code_end = begin + headers->whitespace_3_idx_;
- const size_t kMaxDiv10 = std::numeric_limits<size_t>::max() / 10;
-
- // Convert a string of [0-9]* into an int.
- // Note that this allows for the conversion of response codes which
- // are outside the bounds of normal HTTP response codes (no checking
- // is done to ensure that these are valid-- they're merely parsed)!
- while (parsed_response_code_current < parsed_response_code_end) {
- if (*parsed_response_code_current < '0' ||
- *parsed_response_code_current > '9') {
- *error_code = BalsaFrameEnums::FAILED_CONVERTING_STATUS_CODE_TO_INT;
- return false;
- }
- size_t status_code_x_10 = headers->parsed_response_code_ * 10;
- uint8 c = *parsed_response_code_current - '0';
- if ((headers->parsed_response_code_ > kMaxDiv10) ||
- (std::numeric_limits<size_t>::max() - status_code_x_10) < c) {
- // overflow.
- *error_code = BalsaFrameEnums::FAILED_CONVERTING_STATUS_CODE_TO_INT;
- return false;
- }
- headers->parsed_response_code_ = status_code_x_10 + c;
- ++parsed_response_code_current;
- }
- }
- }
- return true;
-}
-
-// begin - beginning of the firstline
-// end - end of the firstline
-//
-// A precondition for this function is that there is non-whitespace between
-// [begin, end). If this precondition is not met, the function will not perform
-// as expected (and bad things may happen, and it will eat your first, second,
-// and third unborn children!).
-//
-// Another precondition for this function is that [begin, end) includes
-// at most one newline, which must be at the end of the line.
-void BalsaFrame::ProcessFirstLine(const char* begin, const char* end) {
- BalsaFrameEnums::ErrorCode previous_error = last_error_;
- if (!ParseHTTPFirstLine(begin,
- end,
- is_request_,
- max_request_uri_length_,
- headers_,
- &last_error_)) {
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- visitor_->HandleHeaderError(this);
- return;
- }
- if (previous_error != last_error_) {
- visitor_->HandleHeaderWarning(this);
- }
-
- if (is_request_) {
- int version_length =
- headers_->whitespace_4_idx_ - headers_->non_whitespace_3_idx_;
- visitor_->ProcessRequestFirstLine(
- begin + headers_->non_whitespace_1_idx_,
- headers_->whitespace_4_idx_ - headers_->non_whitespace_1_idx_,
- begin + headers_->non_whitespace_1_idx_,
- headers_->whitespace_2_idx_ - headers_->non_whitespace_1_idx_,
- begin + headers_->non_whitespace_2_idx_,
- headers_->whitespace_3_idx_ - headers_->non_whitespace_2_idx_,
- begin + headers_->non_whitespace_3_idx_,
- version_length);
- if (version_length == 0)
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- } else {
- visitor_->ProcessResponseFirstLine(
- begin + headers_->non_whitespace_1_idx_,
- headers_->whitespace_4_idx_ - headers_->non_whitespace_1_idx_,
- begin + headers_->non_whitespace_1_idx_,
- headers_->whitespace_2_idx_ - headers_->non_whitespace_1_idx_,
- begin + headers_->non_whitespace_2_idx_,
- headers_->whitespace_3_idx_ - headers_->non_whitespace_2_idx_,
- begin + headers_->non_whitespace_3_idx_,
- headers_->whitespace_4_idx_ - headers_->non_whitespace_3_idx_);
- }
-}
-
-// 'stream_begin' points to the first character of the headers buffer.
-// 'line_begin' points to the first character of the line.
-// 'current' points to a char which is ':'.
-// 'line_end' points to the position of '\n' + 1.
-// 'line_begin' points to the position of first character of line.
-void BalsaFrame::CleanUpKeyValueWhitespace(
- const char* stream_begin,
- const char* line_begin,
- const char* current,
- const char* line_end,
- HeaderLineDescription* current_header_line) {
- const char* colon_loc = current;
- DCHECK_LT(colon_loc, line_end);
- DCHECK_EQ(':', *colon_loc);
- DCHECK_EQ(':', *current);
- DCHECK_GE(' ', *line_end)
- << "\"" << std::string(line_begin, line_end) << "\"";
-
- // TODO(fenix): Investigate whether or not the bounds tests in the
- // while loops here are redundant, and if so, remove them.
- --current;
- while (current > line_begin && *current <= ' ') --current;
- current += (current != colon_loc);
- current_header_line->key_end_idx = current - stream_begin;
-
- current = colon_loc;
- DCHECK_EQ(':', *current);
- ++current;
- while (current < line_end && *current <= ' ') ++current;
- current_header_line->value_begin_idx = current - stream_begin;
-
- DCHECK_GE(current_header_line->key_end_idx,
- current_header_line->first_char_idx);
- DCHECK_GE(current_header_line->value_begin_idx,
- current_header_line->key_end_idx);
- DCHECK_GE(current_header_line->last_char_idx,
- current_header_line->value_begin_idx);
-}
-
-inline void BalsaFrame::FindColonsAndParseIntoKeyValue() {
- DCHECK(!lines_.empty());
- const char* stream_begin = headers_->OriginalHeaderStreamBegin();
- // The last line is always just a newline (and is uninteresting).
- const Lines::size_type lines_size_m1 = lines_.size() - 1;
-#if __SSE2__
- const __v16qi colons = { ':', ':', ':', ':', ':', ':', ':', ':',
- ':', ':', ':', ':', ':', ':', ':', ':'};
- const char* header_lines_end_m16 = headers_->OriginalHeaderStreamEnd() - 16;
-#endif // __SSE2__
- const char* current = stream_begin + lines_[1].first;
- // This code is a bit more subtle than it may appear at first glance.
- // This code looks for a colon in the current line... but it also looks
- // beyond the current line. If there is no colon in the current line, then
- // for each subsequent line (until the colon which -has- been found is
- // associated with a line), no searching for a colon will be performed. In
- // this way, we minimize the amount of bytes we have scanned for a colon.
- for (Lines::size_type i = 1; i < lines_size_m1;) {
- const char* line_begin = stream_begin + lines_[i].first;
-
- // Here we handle possible continuations. Note that we do not replace
- // the '\n' in the line before a continuation (at least, as of now),
- // which implies that any code which looks for a value must deal with
- // "\r\n", etc -within- the line (and not just at the end of it).
- for (++i; i < lines_size_m1; ++i) {
- const char c = *(stream_begin + lines_[i].first);
- if (c > ' ') {
- // Not a continuation, so stop. Note that if the 'original' i = 1,
- // and the next line is not a continuation, we'll end up with i = 2
- // when we break. This handles the incrementing of i for the outer
- // loop.
- break;
- }
- }
- const char* line_end = stream_begin + lines_[i - 1].second;
- DCHECK_LT(line_begin - stream_begin, line_end - stream_begin);
-
- // We cleanup the whitespace at the end of the line before doing anything
- // else of interest as it allows us to do nothing when irregularly formatted
- // headers are parsed (e.g. those with only keys, only values, or no colon).
- //
- // We're guaranteed to have *line_end > ' ' while line_end >= line_begin.
- --line_end;
- DCHECK_EQ('\n', *line_end)
- << "\"" << std::string(line_begin, line_end) << "\"";
- while (*line_end <= ' ' && line_end > line_begin) {
- --line_end;
- }
- ++line_end;
- DCHECK_GE(' ', *line_end);
- DCHECK_LT(line_begin, line_end);
-
- // We use '0' for the block idx, because we're always writing to the first
- // block from the framer (we do this because the framer requires that the
- // entire header sequence be in a contiguous buffer).
- headers_->header_lines_.push_back(
- HeaderLineDescription(line_begin - stream_begin,
- line_end - stream_begin,
- line_end - stream_begin,
- line_end - stream_begin,
- 0));
- if (current >= line_end) {
- last_error_ = BalsaFrameEnums::HEADER_MISSING_COLON;
- visitor_->HandleHeaderWarning(this);
- // Then the next colon will not be found within this header line-- time
- // to try again with another header-line.
- continue;
- } else if (current < line_begin) {
- // When this condition is true, the last detected colon was part of a
- // previous line. We reset to the beginning of the line as we don't care
- // about the presence of any colon before the beginning of the current
- // line.
- current = line_begin;
- }
-#if __SSE2__
- while (current < header_lines_end_m16) {
- __m128i header_bytes =
- _mm_loadu_si128(reinterpret_cast<const __m128i *>(current));
- __m128i colon_cmp =
- _mm_cmpeq_epi8(header_bytes, reinterpret_cast<__m128i>(colons));
- int colon_msk = _mm_movemask_epi8(colon_cmp);
- if (colon_msk == 0) {
- current += 16;
- continue;
- }
- current += (ffs(colon_msk) - 1);
- if (current > line_end) {
- break;
- }
- goto found_colon;
- }
-#endif // __SSE2__
- for (; current < line_end; ++current) {
- if (*current != ':') {
- continue;
- }
- goto found_colon;
- }
- // If we've gotten to here, then there was no colon
- // in the line. The arguments we passed into the construction
- // for the HeaderLineDescription object should be OK-- it assumes
- // that the entire content is 'key' by default (which is true, as
- // there was no colon, there can be no value). Note that this is a
- // construct which is technically not allowed by the spec.
- last_error_ = BalsaFrameEnums::HEADER_MISSING_COLON;
- visitor_->HandleHeaderWarning(this);
- continue;
- found_colon:
- DCHECK_EQ(*current, ':');
- DCHECK_LE(current - stream_begin, line_end - stream_begin);
- DCHECK_LE(stream_begin - stream_begin, current - stream_begin);
-
- HeaderLineDescription& current_header_line = headers_->header_lines_.back();
- current_header_line.key_end_idx = current - stream_begin;
- current_header_line.value_begin_idx = current_header_line.key_end_idx;
- if (current < line_end) {
- ++current_header_line.key_end_idx;
-
- CleanUpKeyValueWhitespace(stream_begin,
- line_begin,
- current,
- line_end,
- &current_header_line);
- }
- }
-}
-
-void BalsaFrame::ProcessContentLengthLine(
- HeaderLines::size_type line_idx,
- BalsaHeadersEnums::ContentLengthStatus* status,
- size_t* length) {
- const HeaderLineDescription& header_line = headers_->header_lines_[line_idx];
- const char* stream_begin = headers_->OriginalHeaderStreamBegin();
- const char* line_end = stream_begin + header_line.last_char_idx;
- const char* value_begin = (stream_begin + header_line.value_begin_idx);
-
- if (value_begin >= line_end) {
- // There is no non-whitespace value data.
-#if DEBUGFRAMER
- LOG(INFO) << "invalid content-length -- no non-whitespace value data";
-#endif
- *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH;
- return;
- }
-
- *length = 0;
- while (value_begin < line_end) {
- if (*value_begin < '0' || *value_begin > '9') {
- // bad! content-length found, and couldn't parse all of it!
- *status = BalsaHeadersEnums::INVALID_CONTENT_LENGTH;
-#if DEBUGFRAMER
- LOG(INFO) << "invalid content-length - non numeric character detected";
-#endif // DEBUGFRAMER
- return;
- }
- const size_t kMaxDiv10 = std::numeric_limits<size_t>::max() / 10;
- size_t length_x_10 = *length * 10;
- const unsigned char c = *value_begin - '0';
- if (*length > kMaxDiv10 ||
- (std::numeric_limits<size_t>::max() - length_x_10) < c) {
- *status = BalsaHeadersEnums::CONTENT_LENGTH_OVERFLOW;
-#if DEBUGFRAMER
- LOG(INFO) << "content-length overflow";
-#endif // DEBUGFRAMER
- return;
- }
- *length = length_x_10 + c;
- ++value_begin;
- }
-#if DEBUGFRAMER
- LOG(INFO) << "content_length parsed: " << *length;
-#endif // DEBUGFRAMER
- *status = BalsaHeadersEnums::VALID_CONTENT_LENGTH;
-}
-
-void BalsaFrame::ProcessTransferEncodingLine(HeaderLines::size_type line_idx) {
- const HeaderLineDescription& header_line = headers_->header_lines_[line_idx];
- const char* stream_begin = headers_->OriginalHeaderStreamBegin();
- const char* line_end = stream_begin + header_line.last_char_idx;
- const char* value_begin = stream_begin + header_line.value_begin_idx;
- size_t value_length = line_end - value_begin;
-
- if ((value_length == 7) &&
- !strncasecmp(value_begin, "chunked", 7)) {
- headers_->transfer_encoding_is_chunked_ = true;
- } else if ((value_length == 8) &&
- !strncasecmp(value_begin, "identity", 8)) {
- headers_->transfer_encoding_is_chunked_ = false;
- } else {
- last_error_ = BalsaFrameEnums::UNKNOWN_TRANSFER_ENCODING;
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- visitor_->HandleHeaderError(this);
- return;
- }
-}
-
-namespace {
-bool SplitStringPiece(base::StringPiece original, char delim,
- base::StringPiece* before, base::StringPiece* after) {
- const char* p = original.data();
- const char* end = p + original.size();
-
- while (p != end) {
- if (*p == delim) {
- ++p;
- } else {
- const char* start = p;
- while (++p != end && *p != delim) {
- // Skip to the next occurence of the delimiter.
- }
- *before = base::StringPiece(start, p - start);
- if (p != end)
- *after = base::StringPiece(p + 1, end - (p + 1));
- else
- *after = base::StringPiece("");
- StringPieceUtils::RemoveWhitespaceContext(before);
- StringPieceUtils::RemoveWhitespaceContext(after);
- return true;
- }
- }
-
- *before = original;
- *after = "";
- return false;
-}
-
-// TODO(phython): Fix this function to properly deal with quoted values.
-// E.g. ";;foo", "\";;\"", or \"aa;
-// The last example, the semi-colon is a separator between extensions.
-void ProcessChunkExtensionsManual(base::StringPiece all_extensions,
- BalsaHeaders* extensions) {
- base::StringPiece extension;
- base::StringPiece remaining;
- StringPieceUtils::RemoveWhitespaceContext(&all_extensions);
- SplitStringPiece(all_extensions, ';', &extension, &remaining);
- while (!extension.empty()) {
- base::StringPiece key;
- base::StringPiece value;
- SplitStringPiece(extension, '=', &key, &value);
- if (!value.empty()) {
- // Strip quotation marks if they exist.
- if (!value.empty() && value[0] == '"')
- value.remove_prefix(1);
- if (!value.empty() && value[value.length() - 1] == '"')
- value.remove_suffix(1);
- }
-
- extensions->AppendHeader(key, value);
-
- StringPieceUtils::RemoveWhitespaceContext(&remaining);
- SplitStringPiece(remaining, ';', &extension, &remaining);
- }
-}
-
-// TODO(phython): Fix this function to properly deal with quoted values.
-// E.g. ";;foo", "\";;\"", or \"aa;
-// The last example, the semi-colon is a separator between extensions.
-void ProcessChunkExtensionsGoogle3(const char* input, size_t size,
- BalsaHeaders* extensions) {
- std::vector<base::StringPiece> key_values;
- SplitStringPieceToVector(base::StringPiece(input, size), ";",
- &key_values, true);
- for (unsigned int i = 0; i < key_values.size(); ++i) {
- base::StringPiece key = key_values[i].substr(0, key_values[i].find('='));
- base::StringPiece value;
- if (key.length() < key_values[i].length()) {
- value = key_values[i].substr(key.length() + 1);
- // Remove any leading and trailing whitespace.
- StringPieceUtils::RemoveWhitespaceContext(&value);
-
- // Strip quotation marks if they exist.
- if (!value.empty() && value[0] == '"')
- value.remove_prefix(1);
- if (!value.empty() && value[value.length() - 1] == '"')
- value.remove_suffix(1);
- }
-
- // Strip the key whitespace after checking that there is a value.
- StringPieceUtils::RemoveWhitespaceContext(&key);
- extensions->AppendHeader(key, value);
- }
-}
-
-} // anonymous namespace
-
-void BalsaFrame::ProcessChunkExtensions(const char* input, size_t size,
- BalsaHeaders* extensions) {
-#if 0
- ProcessChunkExtensionsGoogle3(input, size, extensions);
-#else
- ProcessChunkExtensionsManual(base::StringPiece(input, size), extensions);
-#endif
-}
-
-void BalsaFrame::ProcessHeaderLines() {
- HeaderLines::size_type content_length_idx = 0;
- HeaderLines::size_type transfer_encoding_idx = 0;
-
- DCHECK(!lines_.empty());
-#if DEBUGFRAMER
- LOG(INFO) << "******@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**********\n";
-#endif // DEBUGFRAMER
-
- // There is no need to attempt to process headers if no header lines exist.
- // There are at least two lines in the message which are not header lines.
- // These two non-header lines are the first line of the message, and the
- // last line of the message (which is an empty line).
- // Thus, we test to see if we have more than two lines total before attempting
- // to parse any header lines.
- if (lines_.size() > 2) {
- const char* stream_begin = headers_->OriginalHeaderStreamBegin();
-
- // Then, for the rest of the header data, we parse these into key-value
- // pairs.
- FindColonsAndParseIntoKeyValue();
- // At this point, we've parsed all of the headers. Time to look for those
- // headers which we require for framing.
- const HeaderLines::size_type
- header_lines_size = headers_->header_lines_.size();
- for (HeaderLines::size_type i = 0; i < header_lines_size; ++i) {
- const HeaderLineDescription& current_header_line =
- headers_->header_lines_[i];
- const char* key_begin =
- (stream_begin + current_header_line.first_char_idx);
- const char* key_end = (stream_begin + current_header_line.key_end_idx);
- const size_t key_len = key_end - key_begin;
- const char c = *key_begin;
-#if DEBUGFRAMER
- LOG(INFO) << "[" << i << "]: " << std::string(key_begin, key_len)
- << " c: '" << c << "' key_len: " << key_len;
-#endif // DEBUGFRAMER
- // If a header begins with either lowercase or uppercase 'c' or 't', then
- // the header may be one of content-length, connection, content-encoding
- // or transfer-encoding. These headers are special, as they change the way
- // that the message is framed, and so the framer is required to search
- // for them.
-
-
- if (c == 'c' || c == 'C') {
- if ((key_len == kContentLengthSize) &&
- 0 == strncasecmp(key_begin, kContentLength, kContentLengthSize)) {
- BalsaHeadersEnums::ContentLengthStatus content_length_status =
- BalsaHeadersEnums::NO_CONTENT_LENGTH;
- size_t length = 0;
- ProcessContentLengthLine(i, &content_length_status, &length);
- if (content_length_idx != 0) { // then we've already seen one!
- if ((headers_->content_length_status_ != content_length_status) ||
- ((headers_->content_length_status_ ==
- BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
- length != headers_->content_length_)) {
- last_error_ = BalsaFrameEnums::MULTIPLE_CONTENT_LENGTH_KEYS;
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- visitor_->HandleHeaderError(this);
- return;
- }
- continue;
- } else {
- content_length_idx = i + 1;
- headers_->content_length_status_ = content_length_status;
- headers_->content_length_ = length;
- content_length_remaining_ = length;
- }
-
- }
- } else if (c == 't' || c == 'T') {
- if ((key_len == kTransferEncodingSize) &&
- 0 == strncasecmp(key_begin, kTransferEncoding,
- kTransferEncodingSize)) {
- if (transfer_encoding_idx != 0) {
- last_error_ = BalsaFrameEnums::MULTIPLE_TRANSFER_ENCODING_KEYS;
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- visitor_->HandleHeaderError(this);
- return;
- }
- transfer_encoding_idx = i + 1;
- }
- } else if (i == 0 && (key_len == 0 || c == ' ')) {
- last_error_ = BalsaFrameEnums::INVALID_HEADER_FORMAT;
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- visitor_->HandleHeaderError(this);
- return;
- }
- }
- if (headers_->transfer_encoding_is_chunked_) {
- headers_->content_length_ = 0;
- headers_->content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH;
- content_length_remaining_ = 0;
- }
- if (transfer_encoding_idx != 0) {
- ProcessTransferEncodingLine(transfer_encoding_idx - 1);
- }
- }
-}
-
-void BalsaFrame::AssignParseStateAfterHeadersHaveBeenParsed() {
- // For responses, can't have a body if the request was a HEAD, or if it is
- // one of these response-codes. rfc2616 section 4.3
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- if (is_request_ ||
- !(request_was_head_ ||
- (headers_->parsed_response_code_ >= 100 &&
- headers_->parsed_response_code_ < 200) ||
- (headers_->parsed_response_code_ == 204) ||
- (headers_->parsed_response_code_ == 304))) {
- // Then we can have a body.
- if (headers_->transfer_encoding_is_chunked_) {
- // Note that
- // if ( Transfer-Encoding: chunked && Content-length: )
- // then Transfer-Encoding: chunked trumps.
- // This is as specified in the spec.
- // rfc2616 section 4.4.3
- parse_state_ = BalsaFrameEnums::READING_CHUNK_LENGTH;
- } else {
- // Errors parsing content-length definitely can cause
- // protocol errors/warnings
- switch (headers_->content_length_status_) {
- // If we have a content-length, and it is parsed
- // properly, there are two options.
- // 1) zero content, in which case the message is done, and
- // 2) nonzero content, in which case we have to
- // consume the body.
- case BalsaHeadersEnums::VALID_CONTENT_LENGTH:
- if (headers_->content_length_ == 0) {
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- } else {
- parse_state_ = BalsaFrameEnums::READING_CONTENT;
- }
- break;
- case BalsaHeadersEnums::CONTENT_LENGTH_OVERFLOW:
- case BalsaHeadersEnums::INVALID_CONTENT_LENGTH:
- // If there were characters left-over after parsing the
- // content length, we should flag an error and stop.
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ = BalsaFrameEnums::UNPARSABLE_CONTENT_LENGTH;
- visitor_->HandleHeaderError(this);
- break;
- // We can have: no transfer-encoding, no content length, and no
- // connection: close...
- // Unfortunately, this case doesn't seem to be covered in the spec.
- // We'll assume that the safest thing to do here is what the google
- // binaries before 2008 already do, which is to assume that
- // everything until the connection is closed is body.
- case BalsaHeadersEnums::NO_CONTENT_LENGTH:
- if (is_request_) {
- base::StringPiece method = headers_->request_method();
- // POSTs and PUTs should have a detectable body length. If they
- // do not we consider it an error.
- if ((method.size() == 4 &&
- strncmp(method.data(), "POST", 4) == 0) ||
- (method.size() == 3 &&
- strncmp(method.data(), "PUT", 3) == 0)) {
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ =
- BalsaFrameEnums::REQUIRED_BODY_BUT_NO_CONTENT_LENGTH;
- visitor_->HandleHeaderError(this);
- break;
- }
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- } else {
- parse_state_ = BalsaFrameEnums::READING_UNTIL_CLOSE;
- last_error_ = BalsaFrameEnums::MAYBE_BODY_BUT_NO_CONTENT_LENGTH;
- visitor_->HandleHeaderWarning(this);
- }
- break;
- // The COV_NF_... statements here provide hints to the apparatus
- // which computes coverage reports/ratios that this code is never
- // intended to be executed, and should technically be impossible.
- // COV_NF_START
- default:
- LOG(FATAL) << "Saw a content_length_status: "
- << headers_->content_length_status_ << " which is unknown.";
- // COV_NF_END
- }
- }
- }
-}
-
-size_t BalsaFrame::ProcessHeaders(const char* message_start,
- size_t message_length) {
- const char* const original_message_start = message_start;
- const char* const message_end = message_start + message_length;
- const char* message_current = message_start;
- const char* checkpoint = message_start;
-
- if (message_length == 0) {
- goto bottom;
- }
-
- while (message_current < message_end) {
- size_t base_idx = headers_->GetReadableBytesFromHeaderStream();
-
- // Yes, we could use strchr (assuming null termination), or
- // memchr, but as it turns out that is slower than this tight loop
- // for the input that we see.
- if (!saw_non_newline_char_) {
- do {
- const char c = *message_current;
- if (c != '\r' && c != '\n') {
- if (c <= ' ') {
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ = BalsaFrameEnums::NO_REQUEST_LINE_IN_REQUEST;
- visitor_->HandleHeaderError(this);
- goto bottom;
- } else {
- saw_non_newline_char_ = true;
- checkpoint = message_start = message_current;
- goto read_real_message;
- }
- }
- ++message_current;
- } while (message_current < message_end);
- goto bottom; // this is necessary to skip 'last_char_was_slash_r' checks
- } else {
- read_real_message:
- // Note that SSE2 can be enabled on certain piii platforms.
-#if __SSE2__
- {
- const char* const message_end_m16 = message_end - 16;
- __v16qi newlines = { '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n',
- '\n', '\n', '\n', '\n', '\n', '\n', '\n', '\n' };
- while (message_current < message_end_m16) {
- // What this does (using compiler intrinsics):
- //
- // Load 16 '\n's into an xmm register
- // Load 16 bytes of currennt message into an xmm register
- // Do byte-wise equals on those two xmm registers
- // Take the first bit of each byte, and put that into the first
- // 16 bits of a mask
- // If the mask is zero, no '\n' found. increment by 16 and try again
- // Else scan forward to find the first set bit.
- // Increment current by the index of the first set bit
- // (ffs returns index of first set bit + 1)
- __m128i msg_bytes =
- _mm_loadu_si128(const_cast<__m128i *>(
- reinterpret_cast<const __m128i *>(message_current)));
- __m128i newline_cmp =
- _mm_cmpeq_epi8(msg_bytes, reinterpret_cast<__m128i>(newlines));
- int newline_msk = _mm_movemask_epi8(newline_cmp);
- if (newline_msk == 0) {
- message_current += 16;
- continue;
- }
- message_current += (ffs(newline_msk) - 1);
- const size_t relative_idx = message_current - message_start;
- const size_t message_current_idx = 1 + base_idx + relative_idx;
- lines_.push_back(std::make_pair(last_slash_n_idx_,
- message_current_idx));
- if (lines_.size() == 1) {
- headers_->WriteFromFramer(checkpoint,
- 1 + message_current - checkpoint);
- checkpoint = message_current + 1;
- const char* begin = headers_->OriginalHeaderStreamBegin();
-#if DEBUGFRAMER
- LOG(INFO) << "First line " << std::string(begin, lines_[0].second);
- LOG(INFO) << "is_request_: " << is_request_;
-#endif
- ProcessFirstLine(begin, begin + lines_[0].second);
- if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ)
- goto process_lines;
- else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR)
- goto bottom;
- }
- const size_t chars_since_last_slash_n = (message_current_idx -
- last_slash_n_idx_);
- last_slash_n_idx_ = message_current_idx;
- if (chars_since_last_slash_n > 2) {
- // We have a slash-n, but the last slash n was
- // more than 2 characters away from this. Thus, we know
- // that this cannot be an end-of-header.
- ++message_current;
- continue;
- }
- if ((chars_since_last_slash_n == 1) ||
- (((message_current > message_start) &&
- (*(message_current - 1) == '\r')) ||
- (last_char_was_slash_r_))) {
- goto process_lines;
- }
- ++message_current;
- }
- }
-#endif // __SSE2__
- while (message_current < message_end) {
- if (*message_current != '\n') {
- ++message_current;
- continue;
- }
- const size_t relative_idx = message_current - message_start;
- const size_t message_current_idx = 1 + base_idx + relative_idx;
- lines_.push_back(std::make_pair(last_slash_n_idx_,
- message_current_idx));
- if (lines_.size() == 1) {
- headers_->WriteFromFramer(checkpoint,
- 1 + message_current - checkpoint);
- checkpoint = message_current + 1;
- const char* begin = headers_->OriginalHeaderStreamBegin();
-#if DEBUGFRAMER
- LOG(INFO) << "First line " << std::string(begin, lines_[0].second);
- LOG(INFO) << "is_request_: " << is_request_;
-#endif
- ProcessFirstLine(begin, begin + lines_[0].second);
- if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ)
- goto process_lines;
- else if (parse_state_ == BalsaFrameEnums::PARSE_ERROR)
- goto bottom;
- }
- const size_t chars_since_last_slash_n = (message_current_idx -
- last_slash_n_idx_);
- last_slash_n_idx_ = message_current_idx;
- if (chars_since_last_slash_n > 2) {
- // false positive.
- ++message_current;
- continue;
- }
- if ((chars_since_last_slash_n == 1) ||
- (((message_current > message_start) &&
- (*(message_current - 1) == '\r')) ||
- (last_char_was_slash_r_))) {
- goto process_lines;
- }
- ++message_current;
- }
- }
- continue;
- process_lines:
- ++message_current;
- DCHECK(message_current >= message_start);
- if (message_current > message_start) {
- headers_->WriteFromFramer(checkpoint, message_current - checkpoint);
- }
-
- // Check if we have exceeded maximum headers length
- // Although we check for this limit before and after we call this function
- // we check it here as well to make sure that in case the visitor changed
- // the max_header_length_ (for example after processing the first line)
- // we handle it gracefully.
- if (headers_->GetReadableBytesFromHeaderStream() > max_header_length_) {
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ = BalsaFrameEnums::HEADERS_TOO_LONG;
- visitor_->HandleHeaderError(this);
- goto bottom;
- }
-
- // Since we know that we won't be writing any more bytes of the header,
- // we tell that to the headers object. The headers object may make
- // more efficient allocation decisions when this is signaled.
- headers_->DoneWritingFromFramer();
- {
- const char* readable_ptr = NULL;
- size_t readable_size = 0;
- headers_->GetReadablePtrFromHeaderStream(&readable_ptr, &readable_size);
- visitor_->ProcessHeaderInput(readable_ptr, readable_size);
- }
-
- // Ok, now that we've written everything into our header buffer, it is
- // time to process the header lines (extract proper values for headers
- // which are important for framing).
- ProcessHeaderLines();
- if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) {
- goto bottom;
- }
- AssignParseStateAfterHeadersHaveBeenParsed();
- if (parse_state_ == BalsaFrameEnums::PARSE_ERROR) {
- goto bottom;
- }
- visitor_->ProcessHeaders(*headers_);
- visitor_->HeaderDone();
- if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ) {
- visitor_->MessageDone();
- }
- goto bottom;
- }
- // If we've gotten to here, it means that we've consumed all of the
- // available input. We need to record whether or not the last character we
- // saw was a '\r' so that a subsequent call to ProcessInput correctly finds
- // a header framing that is split across the two calls.
- last_char_was_slash_r_ = (*(message_end - 1) == '\r');
- DCHECK(message_current >= message_start);
- if (message_current > message_start) {
- headers_->WriteFromFramer(checkpoint, message_current - checkpoint);
- }
- bottom:
- return message_current - original_message_start;
-}
-
-
-size_t BalsaFrame::BytesSafeToSplice() const {
- switch (parse_state_) {
- case BalsaFrameEnums::READING_CHUNK_DATA:
- return chunk_length_remaining_;
- case BalsaFrameEnums::READING_UNTIL_CLOSE:
- return std::numeric_limits<size_t>::max();
- case BalsaFrameEnums::READING_CONTENT:
- return content_length_remaining_;
- default:
- return 0;
- }
-}
-
-void BalsaFrame::BytesSpliced(size_t bytes_spliced) {
- switch (parse_state_) {
- case BalsaFrameEnums::READING_CHUNK_DATA:
- if (chunk_length_remaining_ >= bytes_spliced) {
- chunk_length_remaining_ -= bytes_spliced;
- if (chunk_length_remaining_ == 0) {
- parse_state_ = BalsaFrameEnums::READING_CHUNK_TERM;
- }
- return;
- } else {
- last_error_ =
- BalsaFrameEnums::CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT;
- goto error_exit;
- }
-
- case BalsaFrameEnums::READING_UNTIL_CLOSE:
- return;
-
- case BalsaFrameEnums::READING_CONTENT:
- if (content_length_remaining_ >= bytes_spliced) {
- content_length_remaining_ -= bytes_spliced;
- if (content_length_remaining_ == 0) {
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- visitor_->MessageDone();
- }
- return;
- } else {
- last_error_ =
- BalsaFrameEnums::CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT;
- goto error_exit;
- }
-
- default:
- last_error_ = BalsaFrameEnums::CALLED_BYTES_SPLICED_WHEN_UNSAFE_TO_DO_SO;
- goto error_exit;
- }
-
- error_exit:
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- visitor_->HandleBodyError(this);
-};
-
-// You may note that the state-machine contained within this function has both
-// switch and goto labels for nearly the same thing. For instance, the
-// following two labels refer to the same code block:
-// label_reading_chunk_data:
-// case BalsaFrameEnums::READING_CHUNK_DATA:
-// The 'case' statement is required for the switch statement which occurs when
-// ProcessInput is invoked. The goto label is required as the state-machine
-// does not use a computed goto in any subsequent operations.
-//
-// Since several states exit the state machine for various reasons, there is
-// also one label at the bottom of the function. When it is appropriate to
-// return from the function, that part of the state machine instead issues a
-// goto bottom; This results in less code duplication, and makes debugging
-// easier (as you can add a statement to a section of code which is guaranteed
-// to be invoked when the function is exiting.
-size_t BalsaFrame::ProcessInput(const char* input, size_t size) {
- const char* current = input;
- const char* on_entry = current;
- const char* end = current + size;
-#if DEBUGFRAMER
- LOG(INFO) << "\n=============="
- << BalsaFrameEnums::ParseStateToString(parse_state_)
- << "===============\n";
-#endif // DEBUGFRAMER
-
- DCHECK(headers_ != NULL);
- if (headers_ == NULL) return 0;
-
- if (parse_state_ == BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE) {
- const size_t header_length = headers_->GetReadableBytesFromHeaderStream();
- // Yes, we still have to check this here as the user can change the
- // max_header_length amount!
- // Also it is possible that we have reached the maximum allowed header size,
- // and we have more to consume (remember we are still inside
- // READING_HEADER_AND_FIRSTLINE) in which case we directly declare an error.
- if (header_length > max_header_length_ ||
- (header_length == max_header_length_ && size > 0)) {
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ = BalsaFrameEnums::HEADERS_TOO_LONG;
- visitor_->HandleHeaderError(this);
- goto bottom;
- }
- size_t bytes_to_process = max_header_length_ - header_length;
- if (bytes_to_process > size) {
- bytes_to_process = size;
- }
- current += ProcessHeaders(input, bytes_to_process);
- // If we are still reading headers check if we have crossed the headers
- // limit. Note that we check for >= as opposed to >. This is because if
- // header_length_after equals max_header_length_ and we are still in the
- // parse_state_ BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE we know for
- // sure that the headers limit will be crossed later on
- if (parse_state_ == BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE) {
- // Note that headers_ is valid only if we are still reading headers.
- const size_t header_length_after =
- headers_->GetReadableBytesFromHeaderStream();
- if (header_length_after >= max_header_length_) {
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ = BalsaFrameEnums::HEADERS_TOO_LONG;
- visitor_->HandleHeaderError(this);
- }
- }
- goto bottom;
- } else if (parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ ||
- parse_state_ == BalsaFrameEnums::PARSE_ERROR) {
- // Can do nothing more 'till we're reset.
- goto bottom;
- }
-
- while (current < end) {
- switch (parse_state_) {
- label_reading_chunk_length:
- case BalsaFrameEnums::READING_CHUNK_LENGTH:
- // In this state we read the chunk length.
- // Note that once we hit a character which is not in:
- // [0-9;A-Fa-f\n], we transition to a different state.
- //
- {
- // If we used strtol, etc, we'd have to buffer this line.
- // This is more annoying than simply doing the conversion
- // here. This code accounts for overflow.
- static const signed char buf[] = {
- // %0 %1 %2 %3 %4 %5 %6 %7 %8 \t \n %b %c \r %e %f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -2, -2, -1, -1, -2, -1, -1,
- // %10 %11 %12 %13 %14 %15 %16 %17 %18 %19 %1a %1b %1c %1d %1e %1f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- // ' ' %21 %22 %23 %24 %25 %26 %27 %28 %29 %2a %2b %2c %2d %2e %2f
- -2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- // %30 %31 %32 %33 %34 %35 %36 %37 %38 %39 %3a ';' %3c %3d %3e %3f
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -2, -1, -1, -1, -1,
- // %40 'A' 'B' 'C' 'D' 'E' 'F' %47 %48 %49 %4a %4b %4c %4d %4e %4f
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- // %50 %51 %52 %53 %54 %55 %56 %57 %58 %59 %5a %5b %5c %5d %5e %5f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- // %60 'a' 'b' 'c' 'd' 'e' 'f' %67 %68 %69 %6a %6b %6c %6d %6e %6f
- -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- // %70 %71 %72 %73 %74 %75 %76 %77 %78 %79 %7a %7b %7c %7d %7e %7f
- -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
- };
- // valid cases:
- // "09123\n" // -> 09123
- // "09123\r\n" // -> 09123
- // "09123 \n" // -> 09123
- // "09123 \r\n" // -> 09123
- // "09123 12312\n" // -> 09123
- // "09123 12312\r\n" // -> 09123
- // "09123; foo=bar\n" // -> 09123
- // "09123; foo=bar\r\n" // -> 09123
- // "FFFFFFFFFFFFFFFF\r\n" // -> FFFFFFFFFFFFFFFF
- // "FFFFFFFFFFFFFFFF 22\r\n" // -> FFFFFFFFFFFFFFFF
- // invalid cases:
- // "[ \t]+[^\n]*\n"
- // "FFFFFFFFFFFFFFFFF\r\n" (would overflow)
- // "\r\n"
- // "\n"
- while (current < end) {
- const char c = *current;
- ++current;
- const signed char addition = buf[static_cast<int>(c)];
- if (addition >= 0) {
- chunk_length_character_extracted_ = true;
- size_t length_x_16 = chunk_length_remaining_ * 16;
- const size_t kMaxDiv16 = std::numeric_limits<size_t>::max() / 16;
- if ((chunk_length_remaining_ > kMaxDiv16) ||
- ((std::numeric_limits<size_t>::max() - length_x_16) <
- static_cast<size_t>(addition))) {
- // overflow -- asked for a chunk-length greater than 2^64 - 1!!
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ = BalsaFrameEnums::CHUNK_LENGTH_OVERFLOW;
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- visitor_->HandleChunkingError(this);
- goto bottom;
- }
- chunk_length_remaining_ = length_x_16 + addition;
- continue;
- }
-
- if (!chunk_length_character_extracted_ || addition == -1) {
- // ^[0-9;A-Fa-f][ \t\n] -- was not matched, either because no
- // characters were converted, or an unexpected character was
- // seen.
- parse_state_ = BalsaFrameEnums::PARSE_ERROR;
- last_error_ = BalsaFrameEnums::INVALID_CHUNK_LENGTH;
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- visitor_->HandleChunkingError(this);
- goto bottom;
- }
-
- --current;
- parse_state_ = BalsaFrameEnums::READING_CHUNK_EXTENSION;
- visitor_->ProcessChunkLength(chunk_length_remaining_);
- goto label_reading_chunk_extension;
- }
- }
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- goto bottom; // case BalsaFrameEnums::READING_CHUNK_LENGTH
-
- label_reading_chunk_extension:
- case BalsaFrameEnums::READING_CHUNK_EXTENSION:
- {
- // TODO(phython): Convert this scanning to be 16 bytes at a time if
- // there is data to be read.
- const char* extensions_start = current;
- size_t extensions_length = 0;
- while (current < end) {
- const char c = *current;
- if (c == '\r' || c == '\n') {
- extensions_length =
- (extensions_start == current) ?
- 0 :
- current - extensions_start - 1;
- }
-
- ++current;
- if (c == '\n') {
- chunk_length_character_extracted_ = false;
- visitor_->ProcessChunkExtensions(
- extensions_start, extensions_length);
- if (chunk_length_remaining_ != 0) {
- parse_state_ = BalsaFrameEnums::READING_CHUNK_DATA;
- goto label_reading_chunk_data;
- }
- HeaderFramingFound('\n');
- parse_state_ = BalsaFrameEnums::READING_LAST_CHUNK_TERM;
- goto label_reading_last_chunk_term;
- }
- }
- visitor_->ProcessChunkExtensions(
- extensions_start, extensions_length);
- }
-
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- goto bottom; // case BalsaFrameEnums::READING_CHUNK_EXTENSION
-
- label_reading_chunk_data:
- case BalsaFrameEnums::READING_CHUNK_DATA:
- while (current < end) {
- if (chunk_length_remaining_ == 0) {
- break;
- }
- // read in the chunk
- size_t bytes_remaining = end - current;
- size_t consumed_bytes = (chunk_length_remaining_ < bytes_remaining) ?
- chunk_length_remaining_ : bytes_remaining;
- const char* tmp_current = current + consumed_bytes;
- visitor_->ProcessBodyInput(on_entry, tmp_current - on_entry);
- visitor_->ProcessBodyData(current, consumed_bytes);
- on_entry = current = tmp_current;
- chunk_length_remaining_ -= consumed_bytes;
- }
- if (chunk_length_remaining_ == 0) {
- parse_state_ = BalsaFrameEnums::READING_CHUNK_TERM;
- goto label_reading_chunk_term;
- }
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- goto bottom; // case BalsaFrameEnums::READING_CHUNK_DATA
-
- label_reading_chunk_term:
- case BalsaFrameEnums::READING_CHUNK_TERM:
- while (current < end) {
- const char c = *current;
- ++current;
-
- if (c == '\n') {
- parse_state_ = BalsaFrameEnums::READING_CHUNK_LENGTH;
- goto label_reading_chunk_length;
- }
- }
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- goto bottom; // case BalsaFrameEnums::READING_CHUNK_TERM
-
- label_reading_last_chunk_term:
- case BalsaFrameEnums::READING_LAST_CHUNK_TERM:
- while (current < end) {
- const char c = *current;
-
- if (!HeaderFramingFound(c)) {
- // If not, however, since the spec only suggests that the
- // client SHOULD indicate the presence of trailers, we get to
- // *test* that they did or didn't.
- // If all of the bytes we've seen since:
- // OPTIONAL_WS 0 OPTIONAL_STUFF CRLF
- // are either '\r', or '\n', then we can assume that we don't yet
- // know if we need to parse headers, or if the next byte will make
- // the HeaderFramingFound condition (above) true.
- if (HeaderFramingMayBeFound()) {
- // If true, then we have seen only characters '\r' or '\n'.
- ++current;
-
- // Lets try again! There is no state change here.
- continue;
- } else {
- // If (!HeaderFramingMayBeFound()), then we know that we must be
- // reading the first non CRLF character of a trailer.
- parse_state_ = BalsaFrameEnums::READING_TRAILER;
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- on_entry = current;
- goto label_reading_trailer;
- }
- } else {
- // If we've found a "\r\n\r\n", then the message
- // is done.
- ++current;
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- visitor_->MessageDone();
- goto bottom;
- }
- break; // from while loop
- }
- visitor_->ProcessBodyInput(on_entry, current - on_entry);
- goto bottom; // case BalsaFrameEnums::READING_LAST_CHUNK_TERM
-
- label_reading_trailer:
- case BalsaFrameEnums::READING_TRAILER:
- while (current < end) {
- const char c = *current;
- ++current;
- // TODO(fenix): If we ever care about trailers as part of framing,
- // deal with them here (see below for part of the 'solution')
- // if (LineFramingFound(c)) {
- // trailer_lines_.push_back(make_pair(start_of_line_,
- // trailer_length_ - 1));
- // start_of_line_ = trailer_length_;
- // }
- if (HeaderFramingFound(c)) {
- // ProcessTrailers(visitor_, &trailers_);
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- visitor_->ProcessTrailerInput(on_entry, current - on_entry);
- visitor_->MessageDone();
- goto bottom;
- }
- }
- visitor_->ProcessTrailerInput(on_entry, current - on_entry);
- break; // case BalsaFrameEnums::READING_TRAILER
-
- // Note that there is no label:
- // 'label_reading_until_close'
- // here. This is because the state-machine exists immediately after
- // reading the headers instead of transitioning here (as it would
- // do if it was consuming all the data it could, all the time).
- case BalsaFrameEnums::READING_UNTIL_CLOSE:
- {
- const size_t bytes_remaining = end - current;
- if (bytes_remaining > 0) {
- visitor_->ProcessBodyInput(current, bytes_remaining);
- visitor_->ProcessBodyData(current, bytes_remaining);
- current += bytes_remaining;
- }
- }
- goto bottom; // case BalsaFrameEnums::READING_UNTIL_CLOSE
-
- // label_reading_content:
- case BalsaFrameEnums::READING_CONTENT:
-#if DEBUGFRAMER
- LOG(INFO) << "ReadingContent: " << content_length_remaining_;
-#endif // DEBUGFRAMER
- while (content_length_remaining_ && current < end) {
- // read in the content
- const size_t bytes_remaining = end - current;
- const size_t consumed_bytes =
- (content_length_remaining_ < bytes_remaining) ?
- content_length_remaining_ : bytes_remaining;
- visitor_->ProcessBodyInput(current, consumed_bytes);
- visitor_->ProcessBodyData(current, consumed_bytes);
- current += consumed_bytes;
- content_length_remaining_ -= consumed_bytes;
- }
- if (content_length_remaining_ == 0) {
- parse_state_ = BalsaFrameEnums::MESSAGE_FULLY_READ;
- visitor_->MessageDone();
- }
- goto bottom; // case BalsaFrameEnums::READING_CONTENT
-
- default:
- // The state-machine should never be in a state that isn't handled
- // above. This is a glaring logic error, and we should do something
- // drastic to ensure that this gets looked-at and fixed.
- LOG(FATAL) << "Unknown state: " << parse_state_ // COV_NF_LINE
- << " memory corruption?!"; // COV_NF_LINE
- }
- }
- bottom:
-#if DEBUGFRAMER
- LOG(INFO) << "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\n"
- << std::string(input, current)
- << "\n$$$$$$$$$$$$$$"
- << BalsaFrameEnums::ParseStateToString(parse_state_)
- << "$$$$$$$$$$$$$$$"
- << " consumed: " << (current - input);
- if (Error()) {
- LOG(INFO) << BalsaFrameEnums::ErrorCodeToString(ErrorCode());
- }
-#endif // DEBUGFRAMER
- return current - input;
-}
-
-const uint32 BalsaFrame::kValidTerm1;
-const uint32 BalsaFrame::kValidTerm1Mask;
-const uint32 BalsaFrame::kValidTerm2;
-const uint32 BalsaFrame::kValidTerm2Mask;
-
-} // namespace net
diff --git a/net/tools/flip_server/balsa_frame.h b/net/tools/flip_server/balsa_frame.h
deleted file mode 100644
index 0d3b372..0000000
--- a/net/tools/flip_server/balsa_frame.h
+++ /dev/null
@@ -1,265 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_
-#define NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_
-
-#include <strings.h>
-
-#include <utility>
-#include <vector>
-
-#include "base/compiler_specific.h"
-#include "base/port.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "net/tools/flip_server/balsa_headers.h"
-#include "net/tools/flip_server/balsa_visitor_interface.h"
-#include "net/tools/flip_server/buffer_interface.h"
-#include "net/tools/flip_server/http_message_constants.h"
-#include "net/tools/flip_server/simple_buffer.h"
-
-// For additional debug output, uncomment the following:
-// #define DEBUGFRAMER 1
-
-namespace net {
-
-// BalsaFrame is a 'Model' of a framer (haha).
-// It exists as a proof of concept headers framer.
-class BalsaFrame {
- public:
- typedef std::vector<std::pair<size_t, size_t> > Lines;
-
- typedef BalsaHeaders::HeaderLineDescription HeaderLineDescription;
- typedef BalsaHeaders::HeaderLines HeaderLines;
- typedef BalsaHeaders::HeaderTokenList HeaderTokenList;
-
- // TODO(fenix): get rid of the 'kValidTerm*' stuff by using the 'since last
- // index' strategy. Note that this implies getting rid of the HeaderFramed()
-
- static const uint32 kValidTerm1 = '\n' << 16 |
- '\r' << 8 |
- '\n';
- static const uint32 kValidTerm1Mask = 0xFF << 16 |
- 0xFF << 8 |
- 0xFF;
- static const uint32 kValidTerm2 = '\n' << 8 |
- '\n';
- static const uint32 kValidTerm2Mask = 0xFF << 8 |
- 0xFF;
- BalsaFrame();
- ~BalsaFrame();
-
- // Reset reinitializes all the member variables of the framer and clears the
- // attached header object (but doesn't change the pointer value headers_).
- void Reset();
-
- const BalsaHeaders* const_balsa_headers() const { return headers_; }
- BalsaHeaders* balsa_headers() { return headers_; }
- // The method set_balsa_headers clears the headers provided and attaches them
- // to the framer. This is a required step before the framer will process any
- // input message data.
- // To detach the header object from the framer, use set_balsa_headers(NULL).
- void set_balsa_headers(BalsaHeaders* headers) {
- if (headers_ != headers) {
- headers_ = headers;
- }
- if (headers_) {
- // Clear the headers if they are non-null, even if the new headers are
- // the same as the old.
- headers_->Clear();
- }
- }
-
- void set_balsa_visitor(BalsaVisitorInterface* visitor) {
- visitor_ = visitor;
- if (visitor_ == NULL) {
- visitor_ = &do_nothing_visitor_;
- }
- }
-
- void set_is_request(bool is_request) { is_request_ = is_request; }
-
- bool is_request() const {
- return is_request_;
- }
-
- void set_request_was_head(bool request_was_head) {
- request_was_head_ = request_was_head;
- }
-
- bool request_was_head() const {
- return request_was_head_;
- }
-
- void set_max_header_length(size_t max_header_length) {
- max_header_length_ = max_header_length;
- }
-
- size_t max_header_length() const {
- return max_header_length_;
- }
-
- void set_max_request_uri_length(size_t max_request_uri_length) {
- max_request_uri_length_ = max_request_uri_length;
- }
-
- size_t max_request_uri_length() const {
- return max_request_uri_length_;
- }
-
-
- bool MessageFullyRead() {
- return parse_state_ == BalsaFrameEnums::MESSAGE_FULLY_READ;
- }
-
- BalsaFrameEnums::ParseState ParseState() const { return parse_state_; }
-
-
- bool Error() {
- return parse_state_ == BalsaFrameEnums::PARSE_ERROR;
- }
-
- BalsaFrameEnums::ErrorCode ErrorCode() const { return last_error_; }
-
- const BalsaHeaders* headers() const { return headers_; }
- BalsaHeaders* mutable_headers() { return headers_; }
-
- size_t BytesSafeToSplice() const;
- void BytesSpliced(size_t bytes_spliced);
-
- size_t ProcessInput(const char* input, size_t size);
-
- // Parses input and puts the key, value chunk extensions into extensions.
- // TODO(phython): Find a better data structure to put the extensions into.
- static void ProcessChunkExtensions(const char* input, size_t size,
- BalsaHeaders* extensions);
-
- protected:
- // The utils object needs access to the ParseTokenList in order to do its
- // job.
- friend class BalsaHeadersTokenUtils;
-
- inline void ProcessContentLengthLine(
- size_t line_idx,
- BalsaHeadersEnums::ContentLengthStatus* status,
- size_t* length);
-
- inline void ProcessTransferEncodingLine(size_t line_idx);
-
- void ProcessFirstLine(const char* begin,
- const char* end);
-
- void CleanUpKeyValueWhitespace(
- const char* stream_begin,
- const char* line_begin,
- const char* current,
- const char* line_end,
- HeaderLineDescription* current_header_line);
-
- void FindColonsAndParseIntoKeyValue();
-
- void ProcessHeaderLines();
-
- inline size_t ProcessHeaders(const char* message_start,
- size_t message_length);
-
- void AssignParseStateAfterHeadersHaveBeenParsed();
-
- inline bool LineFramingFound(char current_char) {
- return current_char == '\n';
- }
-
- // TODO(fenix): get rid of the following function and its uses (and
- // replace with something more efficient)
- inline bool HeaderFramingFound(char current_char) {
- // Note that the 'if (current_char == '\n' ...)' test exists to ensure that
- // the HeaderFramingMayBeFound test works properly. In benchmarking done on
- // 2/13/2008, the 'if' actually speeds up performance of the function
- // anyway..
- if (current_char == '\n' || current_char == '\r') {
- term_chars_ <<= 8;
- // This is necessary IFF architecture has > 8 bit char. Alas, I'm
- // paranoid.
- term_chars_ |= current_char & 0xFF;
-
- if ((term_chars_ & kValidTerm1Mask) == kValidTerm1) {
- term_chars_ = 0;
- return true;
- }
- if ((term_chars_ & kValidTerm2Mask) == kValidTerm2) {
- term_chars_ = 0;
- return true;
- }
- } else {
- term_chars_ = 0;
- }
- return false;
- }
-
- inline bool HeaderFramingMayBeFound() const {
- return term_chars_ != 0;
- }
-
- private:
- class DoNothingBalsaVisitor : public BalsaVisitorInterface {
- virtual void ProcessBodyInput(const char *input, size_t size) OVERRIDE {}
- virtual void ProcessBodyData(const char *input, size_t size) OVERRIDE {}
- virtual void ProcessHeaderInput(const char *input, size_t size) OVERRIDE {}
- virtual void ProcessTrailerInput(const char *input, size_t size) OVERRIDE {}
- virtual void ProcessHeaders(const BalsaHeaders& headers) OVERRIDE {}
- virtual void ProcessRequestFirstLine(const char* line_input,
- size_t line_length,
- const char* method_input,
- size_t method_length,
- const char* request_uri_input,
- size_t request_uri_length,
- const char* version_input,
- size_t version_length) OVERRIDE {}
- virtual void ProcessResponseFirstLine(const char *line_input,
- size_t line_length,
- const char *version_input,
- size_t version_length,
- const char *status_input,
- size_t status_length,
- const char *reason_input,
- size_t reason_length) OVERRIDE {}
- virtual void ProcessChunkLength(size_t chunk_length) OVERRIDE {}
- virtual void ProcessChunkExtensions(const char *input,
- size_t size) OVERRIDE {}
- virtual void HeaderDone() OVERRIDE {}
- virtual void MessageDone() OVERRIDE {}
- virtual void HandleHeaderError(BalsaFrame* framer) OVERRIDE {}
- virtual void HandleHeaderWarning(BalsaFrame* framer) OVERRIDE {}
- virtual void HandleChunkingError(BalsaFrame* framer) OVERRIDE {}
- virtual void HandleBodyError(BalsaFrame* framer) OVERRIDE {}
- };
-
- bool last_char_was_slash_r_;
- bool saw_non_newline_char_;
- bool start_was_space_;
- bool chunk_length_character_extracted_;
- bool is_request_; // This is not reset in Reset()
- bool request_was_head_; // This is not reset in Reset()
- size_t max_header_length_; // This is not reset in Reset()
- size_t max_request_uri_length_; // This is not reset in Reset()
- BalsaVisitorInterface* visitor_;
- size_t chunk_length_remaining_;
- size_t content_length_remaining_;
- const char* last_slash_n_loc_;
- const char* last_recorded_slash_n_loc_;
- size_t last_slash_n_idx_;
- uint32 term_chars_;
- BalsaFrameEnums::ParseState parse_state_;
- BalsaFrameEnums::ErrorCode last_error_;
-
- Lines lines_;
-
- BalsaHeaders* headers_; // This is not reset to NULL in Reset().
- DoNothingBalsaVisitor do_nothing_visitor_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_BALSA_FRAME_H_
-
diff --git a/net/tools/flip_server/balsa_frame_test.cc b/net/tools/flip_server/balsa_frame_test.cc
deleted file mode 100644
index 3bb9a42..0000000
--- a/net/tools/flip_server/balsa_frame_test.cc
+++ /dev/null
@@ -1,599 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/balsa_frame.h"
-
-#include <iterator>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_piece.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "net/tools/flip_server/balsa_headers.h"
-#include "testing/gmock/include/gmock/gmock.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-namespace {
-
-using ::base::StringPiece;
-using ::testing::_;
-using ::testing::InSequence;
-using ::testing::SaveArg;
-
-class Visitor : public BalsaVisitorInterface {
- public:
- virtual ~Visitor() {}
- MOCK_METHOD2(ProcessBodyInput, void(const char*, size_t));
- MOCK_METHOD2(ProcessBodyData, void(const char*, size_t));
- MOCK_METHOD2(ProcessHeaderInput, void(const char*, size_t));
- MOCK_METHOD2(ProcessTrailerInput, void(const char*, size_t));
- MOCK_METHOD1(ProcessHeaders, void(const BalsaHeaders&));
- MOCK_METHOD8(ProcessRequestFirstLine, void(const char*,
- size_t,
- const char*,
- size_t,
- const char*,
- size_t,
- const char*,
- size_t));
- MOCK_METHOD8(ProcessResponseFirstLine, void(const char*,
- size_t,
- const char*,
- size_t,
- const char*,
- size_t,
- const char*,
- size_t));
- MOCK_METHOD2(ProcessChunkExtensions, void(const char*, size_t));
- MOCK_METHOD1(ProcessChunkLength, void(size_t));
- MOCK_METHOD0(HeaderDone, void());
- MOCK_METHOD0(MessageDone, void());
- MOCK_METHOD1(HandleHeaderError, void(BalsaFrame*));
- MOCK_METHOD1(HandleHeaderWarning, void(BalsaFrame*));
- MOCK_METHOD1(HandleChunkingError, void(BalsaFrame*));
- MOCK_METHOD1(HandleBodyError, void(BalsaFrame*));
-};
-
-class BalsaFrameTest : public ::testing::Test {
- public:
- virtual void SetUp() OVERRIDE {
- frame_.reset(new BalsaFrame);
- frame_headers_.reset(new BalsaHeaders);
- visitor_.reset(new Visitor);
- frame_->set_balsa_visitor(visitor_.get());
- };
-
- protected:
- scoped_ptr<BalsaFrame> frame_;
- scoped_ptr<BalsaHeaders> frame_headers_;
- scoped_ptr<Visitor> visitor_;
-};
-
-TEST_F(BalsaFrameTest, EmptyFrame) {
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- frame_->ParseState());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(NULL, frame_->const_balsa_headers());
- ASSERT_EQ(NULL, frame_->balsa_headers());
- ASSERT_EQ(NULL, frame_->headers());
- ASSERT_EQ(NULL, frame_->mutable_headers());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
- ASSERT_TRUE(frame_->is_request());
- ASSERT_FALSE(frame_->request_was_head());
-}
-
-TEST_F(BalsaFrameTest, EmptyRequest) {
- const char input[] = "\r\n";
- frame_->set_balsa_headers(frame_headers_.get());
-
- {
- InSequence s;
- // No visitor callback should be called.
- }
- size_t read = frame_->ProcessInput(input, strlen(input));
- EXPECT_EQ(2u, read);
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- frame_->ParseState());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(BalsaFrameEnums::NO_ERROR, frame_->ErrorCode());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-}
-
-TEST_F(BalsaFrameTest, GetRequest) {
- const char input[] = "GET / HTTP/1.0\r\nkey1: value1\r\n\r\n";
- const char* line = NULL;
- size_t line_length = 0;
- const char* method = NULL;
- size_t method_length = 0;
- const char* request_uri = NULL;
- size_t request_uri_length = 0;
- const char* version = NULL;
- size_t version_length = 0;
- const char* header = NULL;
- size_t header_length = 0;
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessRequestFirstLine(_, _, _, _, _, _, _, _))
- .WillOnce(DoAll(SaveArg<0>(&line),
- SaveArg<1>(&line_length),
- SaveArg<2>(&method),
- SaveArg<3>(&method_length),
- SaveArg<4>(&request_uri),
- SaveArg<5>(&request_uri_length),
- SaveArg<6>(&version),
- SaveArg<7>(&version_length)));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _))
- .WillOnce(DoAll(SaveArg<0>(&header), SaveArg<1>(&header_length)));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(*visitor_, MessageDone());
- }
-
- frame_->set_balsa_headers(frame_headers_.get());
- ASSERT_EQ(frame_headers_.get(), frame_->const_balsa_headers());
- ASSERT_EQ(frame_headers_.get(), frame_->balsa_headers());
- ASSERT_EQ(frame_headers_.get(), frame_->headers());
- ASSERT_EQ(frame_headers_.get(), frame_->mutable_headers());
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, frame_->ParseState());
- ASSERT_TRUE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
- ASSERT_EQ("GET / HTTP/1.0", StringPiece(line, line_length));
- ASSERT_EQ("GET", StringPiece(method, method_length));
- ASSERT_EQ("/", StringPiece(request_uri, request_uri_length));
- ASSERT_EQ("HTTP/1.0", StringPiece(version, version_length));
- ASSERT_EQ(input, StringPiece(header, header_length));
-}
-
-TEST_F(BalsaFrameTest, HeadResponse) {
- const char input[] = "HTTP/1.1 200 OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n";
- const char* line = NULL;
- size_t line_length = 0;
- const char* version = NULL;
- size_t version_length = 0;
- const char* status = NULL;
- size_t status_length = 0;
- const char* reason = NULL;
- size_t reason_length = 0;
- const char* header = NULL;
- size_t header_length = 0;
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_is_request(false);
- frame_->set_request_was_head(true);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessResponseFirstLine(_, _, _, _, _, _, _, _))
- .WillOnce(DoAll(SaveArg<0>(&line),
- SaveArg<1>(&line_length),
- SaveArg<2>(&version),
- SaveArg<3>(&version_length),
- SaveArg<4>(&status),
- SaveArg<5>(&status_length),
- SaveArg<6>(&reason),
- SaveArg<7>(&reason_length)));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _))
- .WillOnce(DoAll(SaveArg<0>(&header), SaveArg<1>(&header_length)));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(*visitor_, MessageDone());
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, frame_->ParseState());
- ASSERT_TRUE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-
- ASSERT_EQ("HTTP/1.1 200 OK", StringPiece(line, line_length));
- ASSERT_EQ("HTTP/1.1", StringPiece(version, version_length));
- ASSERT_EQ("200", StringPiece(status, status_length));
- ASSERT_EQ("OK", StringPiece(reason, reason_length));
- ASSERT_EQ("HTTP/1.1 200 OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n",
- StringPiece(header, header_length));
-}
-
-TEST_F(BalsaFrameTest, GetResponse) {
- const char input[] = "HTTP/1.1 200 OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n"
- "hello, world\r\n";
- const char* line = NULL;
- size_t line_length = 0;
- const char* version = NULL;
- size_t version_length = 0;
- const char* status = NULL;
- size_t status_length = 0;
- const char* reason = NULL;
- size_t reason_length = 0;
- const char* header = NULL;
- size_t header_length = 0;
- const char* body = NULL;
- size_t body_length = 0;
- const char* body_data = NULL;
- size_t body_data_length = 0;
- testing::MockFunction<void(int)> checkpoint;
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_is_request(false);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessResponseFirstLine(_, _, _, _, _, _, _, _))
- .WillOnce(DoAll(SaveArg<0>(&line),
- SaveArg<1>(&line_length),
- SaveArg<2>(&version),
- SaveArg<3>(&version_length),
- SaveArg<4>(&status),
- SaveArg<5>(&status_length),
- SaveArg<6>(&reason),
- SaveArg<7>(&reason_length)));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _))
- .WillOnce(DoAll(SaveArg<0>(&header), SaveArg<1>(&header_length)));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*visitor_, ProcessBodyInput(_, _))
- .WillOnce(DoAll(SaveArg<0>(&body), SaveArg<1>(&body_length)));
- EXPECT_CALL(*visitor_, ProcessBodyData(_, _))
- .WillOnce(DoAll(SaveArg<0>(&body_data), SaveArg<1>(&body_data_length)));
- EXPECT_CALL(*visitor_, MessageDone());
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(65u, read);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- checkpoint.Call(0);
- read += frame_->ProcessInput(&input[read], strlen(input) - read);
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, frame_->ParseState());
- ASSERT_TRUE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-
- ASSERT_EQ("HTTP/1.1 200 OK", StringPiece(line, line_length));
- ASSERT_EQ("HTTP/1.1", StringPiece(version, version_length));
- ASSERT_EQ("200", StringPiece(status, status_length));
- ASSERT_EQ("OK", StringPiece(reason, reason_length));
- ASSERT_EQ("HTTP/1.1 200 OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n",
- StringPiece(header, header_length));
- ASSERT_EQ("hello, world\r\n", StringPiece(body, body_length));
- ASSERT_EQ("hello, world\r\n", StringPiece(body_data, body_data_length));
-}
-
-TEST_F(BalsaFrameTest, Reset) {
- const char input[] = "GET / HTTP/1.0\r\nkey1: value1\r\n\r\n";
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessRequestFirstLine(_, _, _, _, _, _, _, _));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(*visitor_, MessageDone());
- }
-
- frame_->set_balsa_headers(frame_headers_.get());
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, frame_->ParseState());
- ASSERT_TRUE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
-
- frame_->Reset();
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- frame_->ParseState());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
-}
-
-TEST_F(BalsaFrameTest, InvalidStatusCode) {
- const char input[] = "HTTP/1.1 InvalidStatusCode OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n"
- "hello, world\r\n";
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_is_request(false);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, HandleHeaderError(frame_.get()));
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(30u, read);
- ASSERT_EQ(BalsaFrameEnums::PARSE_ERROR, frame_->ParseState());
- ASSERT_EQ(BalsaFrameEnums::FAILED_CONVERTING_STATUS_CODE_TO_INT,
- frame_->ErrorCode());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_TRUE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-}
-
-TEST_F(BalsaFrameTest, ResetError) {
- const char input[] = "HTTP/1.1 InvalidStatusCode OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n"
- "hello, world\r\n";
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_is_request(false);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, HandleHeaderError(frame_.get()));
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(30u, read);
- ASSERT_EQ(BalsaFrameEnums::PARSE_ERROR, frame_->ParseState());
- ASSERT_EQ(BalsaFrameEnums::FAILED_CONVERTING_STATUS_CODE_TO_INT,
- frame_->ErrorCode());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_TRUE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-
- frame_->Reset();
- ASSERT_EQ(BalsaFrameEnums::READING_HEADER_AND_FIRSTLINE,
- frame_->ParseState());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
-}
-
-TEST_F(BalsaFrameTest, RequestURITooLong) {
- const char input[] = "GET / HTTP/1.0\r\n\r\n";
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_max_request_uri_length(0);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, HandleHeaderError(frame_.get()));
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(15u, read);
- ASSERT_EQ(BalsaFrameEnums::PARSE_ERROR, frame_->ParseState());
- ASSERT_EQ(BalsaFrameEnums::REQUEST_URI_TOO_LONG, frame_->ErrorCode());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_TRUE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-}
-
-TEST_F(BalsaFrameTest, HeadersTooLong) {
- const char input[] = "GET / HTTP/1.0\r\n\r\n";
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_max_header_length(0);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, HandleHeaderError(frame_.get()));
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(0u, read);
- ASSERT_EQ(BalsaFrameEnums::PARSE_ERROR, frame_->ParseState());
- ASSERT_EQ(BalsaFrameEnums::HEADERS_TOO_LONG, frame_->ErrorCode());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_TRUE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-}
-
-TEST_F(BalsaFrameTest, InvalidHeader) {
- const char input[] = "GET / HTTP/1.0\r\n"
- "foo bar baz\r\n"
- "Content-Type: text/plain\r\n\r\n";
- const char* line = NULL;
- size_t line_length = 0;
- const char* method = NULL;
- size_t method_length = 0;
- const char* request_uri = NULL;
- size_t request_uri_length = 0;
- const char* version = NULL;
- size_t version_length = 0;
-
- frame_->set_balsa_headers(frame_headers_.get());
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessRequestFirstLine(_, _, _, _, _, _, _, _))
- .WillOnce(DoAll(SaveArg<0>(&line),
- SaveArg<1>(&line_length),
- SaveArg<2>(&method),
- SaveArg<3>(&method_length),
- SaveArg<4>(&request_uri),
- SaveArg<5>(&request_uri_length),
- SaveArg<6>(&version),
- SaveArg<7>(&version_length)));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _));
- EXPECT_CALL(*visitor_, HandleHeaderWarning(frame_.get()));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(*visitor_, MessageDone());
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, frame_->ParseState());
- ASSERT_EQ(BalsaFrameEnums::HEADER_MISSING_COLON, frame_->ErrorCode());
- ASSERT_TRUE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
- ASSERT_EQ("GET / HTTP/1.0", StringPiece(line, line_length));
- ASSERT_EQ("GET", StringPiece(method, method_length));
- ASSERT_EQ("/", StringPiece(request_uri, request_uri_length));
- ASSERT_EQ("HTTP/1.0", StringPiece(version, version_length));
- ASSERT_EQ(2, std::distance(frame_headers_->header_lines_begin(),
- frame_headers_->header_lines_end()));
-}
-
-TEST_F(BalsaFrameTest, GetResponseSplit) {
- const char input[] = "HTTP/1.1 200 OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n"
- "hello";
- const char input2[] = ", world\r\n";
- const char* body1 = NULL;
- size_t body1_length = 0;
- const char* body1_data = NULL;
- size_t body1_data_length = 0;
- const char* body2 = NULL;
- size_t body2_length = 0;
- const char* body2_data = NULL;
- size_t body2_data_length = 0;
- testing::MockFunction<void(int)> checkpoint;
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_is_request(false);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessResponseFirstLine(_, _, _, _, _, _, _, _));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*visitor_, ProcessBodyInput(_, _))
- .WillOnce(DoAll(SaveArg<0>(&body1), SaveArg<1>(&body1_length)));
- EXPECT_CALL(*visitor_, ProcessBodyData(_, _))
- .WillOnce(DoAll(SaveArg<0>(&body1_data),
- SaveArg<1>(&body1_data_length)));
- EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(*visitor_, ProcessBodyInput(_, _))
- .WillOnce(DoAll(SaveArg<0>(&body2), SaveArg<1>(&body2_length)));
- EXPECT_CALL(*visitor_, ProcessBodyData(_, _))
- .WillOnce(DoAll(SaveArg<0>(&body2_data),
- SaveArg<1>(&body2_data_length)));
- EXPECT_CALL(*visitor_, MessageDone());
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(65u, read);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- checkpoint.Call(0);
- read += frame_->ProcessInput(&input[read], strlen(input) - read);
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- checkpoint.Call(1);
- ASSERT_EQ(9u, frame_->BytesSafeToSplice());
- read = frame_->ProcessInput(input2, strlen(input2));
- ASSERT_EQ(strlen(input2), read);
-
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, frame_->ParseState());
- ASSERT_TRUE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
- ASSERT_EQ("hello", StringPiece(body1, body1_length));
- ASSERT_EQ("hello", StringPiece(body1_data, body1_data_length));
- ASSERT_EQ(", world\r\n", StringPiece(body2, body2_length));
- ASSERT_EQ(", world\r\n", StringPiece(body2_data, body2_data_length));
-}
-
-TEST_F(BalsaFrameTest, GetResponseBytesSpliced) {
- const char input[] = "HTTP/1.1 200 OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n"
- "hello";
- testing::MockFunction<void(int)> checkpoint;
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_is_request(false);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessResponseFirstLine(_, _, _, _, _, _, _, _));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*visitor_, ProcessBodyInput(_, _));
- EXPECT_CALL(*visitor_, ProcessBodyData(_, _));
- EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(checkpoint, Call(2));
- EXPECT_CALL(*visitor_, MessageDone());
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(65u, read);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- checkpoint.Call(0);
- read += frame_->ProcessInput(&input[read], strlen(input) - read);
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- ASSERT_EQ(9u, frame_->BytesSafeToSplice());
- checkpoint.Call(1);
- frame_->BytesSpliced(5);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- ASSERT_EQ(4u, frame_->BytesSafeToSplice());
- checkpoint.Call(2);
- frame_->BytesSpliced(4);
- ASSERT_EQ(BalsaFrameEnums::MESSAGE_FULLY_READ, frame_->ParseState());
-
- ASSERT_TRUE(frame_->MessageFullyRead());
- ASSERT_FALSE(frame_->Error());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-}
-
-TEST_F(BalsaFrameTest, GetResponseBytesSplicedTooMany) {
- const char input[] = "HTTP/1.1 200 OK\r\n"
- "Content-type: text/plain\r\n"
- "Content-Length: 14\r\n\r\n"
- "hello";
- testing::MockFunction<void(int)> checkpoint;
-
- frame_->set_balsa_headers(frame_headers_.get());
- frame_->set_is_request(false);
-
- {
- InSequence s;
- EXPECT_CALL(*visitor_, ProcessResponseFirstLine(_, _, _, _, _, _, _, _));
- EXPECT_CALL(*visitor_, ProcessHeaderInput(_, _));
- EXPECT_CALL(*visitor_, ProcessHeaders(_));
- EXPECT_CALL(*visitor_, HeaderDone());
- EXPECT_CALL(checkpoint, Call(0));
- EXPECT_CALL(*visitor_, ProcessBodyInput(_, _));
- EXPECT_CALL(*visitor_, ProcessBodyData(_, _));
- EXPECT_CALL(checkpoint, Call(1));
- EXPECT_CALL(*visitor_, HandleBodyError(frame_.get()));
- }
-
- size_t read = frame_->ProcessInput(input, strlen(input));
- ASSERT_EQ(65u, read);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- checkpoint.Call(0);
- read += frame_->ProcessInput(&input[read], strlen(input) - read);
- ASSERT_EQ(strlen(input), read);
- ASSERT_EQ(BalsaFrameEnums::READING_CONTENT, frame_->ParseState());
- ASSERT_EQ(9u, frame_->BytesSafeToSplice());
- checkpoint.Call(1);
- frame_->BytesSpliced(99);
- ASSERT_EQ(BalsaFrameEnums::PARSE_ERROR, frame_->ParseState());
- ASSERT_FALSE(frame_->MessageFullyRead());
- ASSERT_TRUE(frame_->Error());
- ASSERT_EQ(
- BalsaFrameEnums::CALLED_BYTES_SPLICED_AND_EXCEEDED_SAFE_SPLICE_AMOUNT,
- frame_->ErrorCode());
- ASSERT_EQ(0u, frame_->BytesSafeToSplice());
-}
-
-} // namespace
-
-} // namespace net
diff --git a/net/tools/flip_server/balsa_headers.cc b/net/tools/flip_server/balsa_headers.cc
deleted file mode 100644
index 040c012..0000000
--- a/net/tools/flip_server/balsa_headers.cc
+++ /dev/null
@@ -1,965 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/balsa_headers.h"
-
-#include <stdio.h>
-#include <algorithm>
-#include <ext/hash_set>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/port.h"
-#include "base/strings/stringprintf.h"
-#include "base/strings/string_piece.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "net/tools/flip_server/buffer_interface.h"
-#include "net/tools/flip_server/simple_buffer.h"
-#include "third_party/tcmalloc/chromium/src/base/googleinit.h"
-// #include "util/gtl/iterator_adaptors-inl.h"
-// #include "util/gtl/map-util.h"
-
-namespace {
-
-const char kContentLength[] = "Content-Length";
-const char kTransferEncoding[] = "Transfer-Encoding";
-const char kSpaceChar = ' ';
-
-__gnu_cxx::hash_set<base::StringPiece,
- net::StringPieceCaseHash,
- net::StringPieceCaseEqual> g_multivalued_headers;
-
-void InitMultivaluedHeaders() {
- g_multivalued_headers.insert("accept");
- g_multivalued_headers.insert("accept-charset");
- g_multivalued_headers.insert("accept-encoding");
- g_multivalued_headers.insert("accept-language");
- g_multivalued_headers.insert("accept-ranges");
- g_multivalued_headers.insert("allow");
- g_multivalued_headers.insert("cache-control");
- g_multivalued_headers.insert("connection");
- g_multivalued_headers.insert("content-encoding");
- g_multivalued_headers.insert("content-language");
- g_multivalued_headers.insert("expect");
- g_multivalued_headers.insert("if-match");
- g_multivalued_headers.insert("if-none-match");
- g_multivalued_headers.insert("pragma");
- g_multivalued_headers.insert("proxy-authenticate");
- g_multivalued_headers.insert("te");
- g_multivalued_headers.insert("trailer");
- g_multivalued_headers.insert("transfer-encoding");
- g_multivalued_headers.insert("upgrade");
- g_multivalued_headers.insert("vary");
- g_multivalued_headers.insert("via");
- g_multivalued_headers.insert("warning");
- g_multivalued_headers.insert("www-authenticate");
- // Not mentioned in RFC 2616, but it can have multiple values.
- g_multivalued_headers.insert("set-cookie");
-}
-
-REGISTER_MODULE_INITIALIZER(multivalued_headers, InitMultivaluedHeaders());
-
-const int kFastToBufferSize = 32; // I think 22 is adequate, but anyway..
-
-} // namespace
-
-namespace net {
-
-const size_t BalsaBuffer::kDefaultBlocksize;
-
-BalsaHeaders::iterator_base::iterator_base() : headers_(NULL), idx_(0) { }
-
-BalsaHeaders::iterator_base::iterator_base(const iterator_base& it)
- : headers_(it.headers_),
- idx_(it.idx_) {
-}
-
-std::ostream& BalsaHeaders::iterator_base::operator<<(std::ostream& os) const {
- os << "[" << this->headers_ << ", " << this->idx_ << "]";
- return os;
-}
-
-BalsaHeaders::iterator_base::iterator_base(const BalsaHeaders* headers,
- HeaderLines::size_type index)
- : headers_(headers),
- idx_(index) {
-}
-
-BalsaBuffer::~BalsaBuffer() {
- CleanupBlocksStartingFrom(0);
-}
-
-// Returns the total amount of memory used by the buffer blocks.
-size_t BalsaBuffer::GetTotalBufferBlockSize() const {
- size_t buffer_size = 0;
- for (Blocks::const_iterator iter = blocks_.begin();
- iter != blocks_.end();
- ++iter) {
- buffer_size += iter->buffer_size;
- }
- return buffer_size;
-}
-
-void BalsaBuffer::WriteToContiguousBuffer(const base::StringPiece& sp) {
- if (sp.empty()) {
- return;
- }
- CHECK(can_write_to_contiguous_buffer_);
- DCHECK_GE(blocks_.size(), 1u);
- if (blocks_[0].buffer == NULL && sp.size() <= blocksize_) {
- blocks_[0] = AllocBlock();
- memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
- } else if (blocks_[0].bytes_free < sp.size()) {
- // the first block isn't big enough, resize it.
- const size_t old_storage_size_used = blocks_[0].bytes_used();
- const size_t new_storage_size = old_storage_size_used + sp.size();
- char* new_storage = new char[new_storage_size];
- char* old_storage = blocks_[0].buffer;
- if (old_storage_size_used) {
- memcpy(new_storage, old_storage, old_storage_size_used);
- }
- memcpy(new_storage + old_storage_size_used, sp.data(), sp.size());
- blocks_[0].buffer = new_storage;
- blocks_[0].bytes_free = sp.size();
- blocks_[0].buffer_size = new_storage_size;
- delete[] old_storage;
- } else {
- memcpy(blocks_[0].start_of_unused_bytes(), sp.data(), sp.size());
- }
- blocks_[0].bytes_free -= sp.size();
-}
-
-base::StringPiece BalsaBuffer::Write(const base::StringPiece& sp,
- Blocks::size_type* block_buffer_idx) {
- if (sp.empty()) {
- return sp;
- }
- char* storage = Reserve(sp.size(), block_buffer_idx);
- memcpy(storage, sp.data(), sp.size());
- return base::StringPiece(storage, sp.size());
-}
-
-char* BalsaBuffer::Reserve(size_t size,
- Blocks::size_type* block_buffer_idx) {
- // There should always be a 'first_block', even if it
- // contains nothing.
- DCHECK_GE(blocks_.size(), 1u);
- BufferBlock* block = NULL;
- Blocks::size_type block_idx = can_write_to_contiguous_buffer_ ? 1 : 0;
- for (; block_idx < blocks_.size(); ++block_idx) {
- if (blocks_[block_idx].bytes_free >= size) {
- block = &blocks_[block_idx];
- break;
- }
- }
- if (block == NULL) {
- if (blocksize_ < size) {
- blocks_.push_back(AllocCustomBlock(size));
- } else {
- blocks_.push_back(AllocBlock());
- }
- block = &blocks_.back();
- }
-
- char* storage = block->start_of_unused_bytes();
- block->bytes_free -= size;
- if (block_buffer_idx) {
- *block_buffer_idx = block_idx;
- }
- return storage;
-}
-
-void BalsaBuffer::Clear() {
- CHECK(!blocks_.empty());
- if (blocksize_ == blocks_[0].buffer_size) {
- CleanupBlocksStartingFrom(1);
- blocks_[0].bytes_free = blocks_[0].buffer_size;
- } else {
- CleanupBlocksStartingFrom(0);
- blocks_.push_back(AllocBlock());
- }
- DCHECK_GE(blocks_.size(), 1u);
- can_write_to_contiguous_buffer_ = true;
-}
-
-void BalsaBuffer::Swap(BalsaBuffer* b) {
- blocks_.swap(b->blocks_);
- std::swap(can_write_to_contiguous_buffer_,
- b->can_write_to_contiguous_buffer_);
- std::swap(blocksize_, b->blocksize_);
-}
-
-void BalsaBuffer::CopyFrom(const BalsaBuffer& b) {
- CleanupBlocksStartingFrom(0);
- blocks_.resize(b.blocks_.size());
- for (Blocks::size_type i = 0; i < blocks_.size(); ++i) {
- blocks_[i] = CopyBlock(b.blocks_[i]);
- }
- blocksize_ = b.blocksize_;
- can_write_to_contiguous_buffer_ = b.can_write_to_contiguous_buffer_;
-}
-
-BalsaBuffer::BalsaBuffer()
- : blocksize_(kDefaultBlocksize), can_write_to_contiguous_buffer_(true) {
- blocks_.push_back(AllocBlock());
-}
-
-BalsaBuffer::BalsaBuffer(size_t blocksize) :
- blocksize_(blocksize), can_write_to_contiguous_buffer_(true) {
- blocks_.push_back(AllocBlock());
-}
-
-BalsaBuffer::BufferBlock BalsaBuffer::AllocBlock() {
- return AllocCustomBlock(blocksize_);
-}
-
-BalsaBuffer::BufferBlock BalsaBuffer::AllocCustomBlock(size_t blocksize) {
- return BufferBlock(new char[blocksize], blocksize, blocksize);
-}
-
-BalsaBuffer::BufferBlock BalsaBuffer::CopyBlock(const BufferBlock& b) {
- BufferBlock block = b;
- if (b.buffer == NULL) {
- return block;
- }
-
- block.buffer = new char[b.buffer_size];
- memcpy(block.buffer, b.buffer, b.bytes_used());
- return block;
-}
-
-void BalsaBuffer::CleanupBlocksStartingFrom(Blocks::size_type start_idx) {
- for (Blocks::size_type i = start_idx; i < blocks_.size(); ++i) {
- delete[] blocks_[i].buffer;
- }
- blocks_.resize(start_idx);
-}
-
-BalsaHeaders::const_header_lines_key_iterator::const_header_lines_key_iterator(
- const const_header_lines_key_iterator& other)
- : iterator_base(other),
- key_(other.key_) {
-}
-
-BalsaHeaders::const_header_lines_key_iterator::const_header_lines_key_iterator(
- const BalsaHeaders* headers,
- HeaderLines::size_type index,
- const base::StringPiece& key)
- : iterator_base(headers, index),
- key_(key) {
-}
-
-BalsaHeaders::const_header_lines_key_iterator::const_header_lines_key_iterator(
- const BalsaHeaders* headers,
- HeaderLines::size_type index)
- : iterator_base(headers, index) {
-}
-
-BalsaHeaders::BalsaHeaders()
- : balsa_buffer_(4096),
- content_length_(0),
- content_length_status_(BalsaHeadersEnums::NO_CONTENT_LENGTH),
- parsed_response_code_(0),
- firstline_buffer_base_idx_(0),
- whitespace_1_idx_(0),
- non_whitespace_1_idx_(0),
- whitespace_2_idx_(0),
- non_whitespace_2_idx_(0),
- whitespace_3_idx_(0),
- non_whitespace_3_idx_(0),
- whitespace_4_idx_(0),
- end_of_firstline_idx_(0),
- transfer_encoding_is_chunked_(false) {
-}
-
-BalsaHeaders::~BalsaHeaders() {}
-
-void BalsaHeaders::Clear() {
- balsa_buffer_.Clear();
- transfer_encoding_is_chunked_ = false;
- content_length_ = 0;
- content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH;
- parsed_response_code_ = 0;
- firstline_buffer_base_idx_ = 0;
- whitespace_1_idx_ = 0;
- non_whitespace_1_idx_ = 0;
- whitespace_2_idx_ = 0;
- non_whitespace_2_idx_ = 0;
- whitespace_3_idx_ = 0;
- non_whitespace_3_idx_ = 0;
- whitespace_4_idx_ = 0;
- end_of_firstline_idx_ = 0;
- header_lines_.clear();
-}
-
-void BalsaHeaders::Swap(BalsaHeaders* other) {
- // Protect against swapping with self.
- if (this == other) return;
-
- balsa_buffer_.Swap(&other->balsa_buffer_);
-
- bool tmp_bool = transfer_encoding_is_chunked_;
- transfer_encoding_is_chunked_ = other->transfer_encoding_is_chunked_;
- other->transfer_encoding_is_chunked_ = tmp_bool;
-
- size_t tmp_size_t = content_length_;
- content_length_ = other->content_length_;
- other->content_length_ = tmp_size_t;
-
- BalsaHeadersEnums::ContentLengthStatus tmp_status =
- content_length_status_;
- content_length_status_ = other->content_length_status_;
- other->content_length_status_ = tmp_status;
-
- tmp_size_t = parsed_response_code_;
- parsed_response_code_ = other->parsed_response_code_;
- other->parsed_response_code_ = tmp_size_t;
-
- BalsaBuffer::Blocks::size_type tmp_blk_idx = firstline_buffer_base_idx_;
- firstline_buffer_base_idx_ = other->firstline_buffer_base_idx_;
- other->firstline_buffer_base_idx_ = tmp_blk_idx;
-
- tmp_size_t = whitespace_1_idx_;
- whitespace_1_idx_ = other->whitespace_1_idx_;
- other->whitespace_1_idx_ = tmp_size_t;
-
- tmp_size_t = non_whitespace_1_idx_;
- non_whitespace_1_idx_ = other->non_whitespace_1_idx_;
- other->non_whitespace_1_idx_ = tmp_size_t;
-
- tmp_size_t = whitespace_2_idx_;
- whitespace_2_idx_ = other->whitespace_2_idx_;
- other->whitespace_2_idx_ = tmp_size_t;
-
- tmp_size_t = non_whitespace_2_idx_;
- non_whitespace_2_idx_ = other->non_whitespace_2_idx_;
- other->non_whitespace_2_idx_ = tmp_size_t;
-
- tmp_size_t = whitespace_3_idx_;
- whitespace_3_idx_ = other->whitespace_3_idx_;
- other->whitespace_3_idx_ = tmp_size_t;
-
- tmp_size_t = non_whitespace_3_idx_;
- non_whitespace_3_idx_ = other->non_whitespace_3_idx_;
- other->non_whitespace_3_idx_ = tmp_size_t;
-
- tmp_size_t = whitespace_4_idx_;
- whitespace_4_idx_ = other->whitespace_4_idx_;
- other->whitespace_4_idx_ = tmp_size_t;
-
- tmp_size_t = end_of_firstline_idx_;
- end_of_firstline_idx_ = other->end_of_firstline_idx_;
- other->end_of_firstline_idx_ = tmp_size_t;
-
- swap(header_lines_, other->header_lines_);
-}
-
-void BalsaHeaders::CopyFrom(const BalsaHeaders& other) {
- // Protect against copying with self.
- if (this == &other) return;
-
- balsa_buffer_.CopyFrom(other.balsa_buffer_);
- transfer_encoding_is_chunked_ = other.transfer_encoding_is_chunked_;
- content_length_ = other.content_length_;
- content_length_status_ = other.content_length_status_;
- parsed_response_code_ = other.parsed_response_code_;
- firstline_buffer_base_idx_ = other.firstline_buffer_base_idx_;
- whitespace_1_idx_ = other.whitespace_1_idx_;
- non_whitespace_1_idx_ = other.non_whitespace_1_idx_;
- whitespace_2_idx_ = other.whitespace_2_idx_;
- non_whitespace_2_idx_ = other.non_whitespace_2_idx_;
- whitespace_3_idx_ = other.whitespace_3_idx_;
- non_whitespace_3_idx_ = other.non_whitespace_3_idx_;
- whitespace_4_idx_ = other.whitespace_4_idx_;
- end_of_firstline_idx_ = other.end_of_firstline_idx_;
- header_lines_ = other.header_lines_;
-}
-
-void BalsaHeaders::AddAndMakeDescription(const base::StringPiece& key,
- const base::StringPiece& value,
- HeaderLineDescription* d) {
- CHECK(d != NULL);
- // + 2 to size for ": "
- size_t line_size = key.size() + 2 + value.size();
- BalsaBuffer::Blocks::size_type block_buffer_idx = 0;
- char* storage = balsa_buffer_.Reserve(line_size, &block_buffer_idx);
- size_t base_idx = storage - GetPtr(block_buffer_idx);
-
- char* cur_loc = storage;
- memcpy(cur_loc, key.data(), key.size());
- cur_loc += key.size();
- *cur_loc = ':';
- ++cur_loc;
- *cur_loc = ' ';
- ++cur_loc;
- memcpy(cur_loc, value.data(), value.size());
- *d = HeaderLineDescription(base_idx,
- base_idx + key.size(),
- base_idx + key.size() + 2,
- base_idx + key.size() + 2 + value.size(),
- block_buffer_idx);
-}
-
-void BalsaHeaders::AppendOrPrependAndMakeDescription(
- const base::StringPiece& key,
- const base::StringPiece& value,
- bool append,
- HeaderLineDescription* d) {
- // Figure out how much space we need to reserve for the new header size.
- size_t old_value_size = d->last_char_idx - d->value_begin_idx;
- if (old_value_size == 0) {
- AddAndMakeDescription(key, value, d);
- return;
- }
- base::StringPiece old_value(GetPtr(d->buffer_base_idx) + d->value_begin_idx,
- old_value_size);
-
- BalsaBuffer::Blocks::size_type block_buffer_idx = 0;
- // + 3 because we potentially need to add ": ", and "," to the line.
- size_t new_size = key.size() + 3 + old_value_size + value.size();
- char* storage = balsa_buffer_.Reserve(new_size, &block_buffer_idx);
- size_t base_idx = storage - GetPtr(block_buffer_idx);
-
- base::StringPiece first_value = old_value;
- base::StringPiece second_value = value;
- if (!append) { // !append == prepend
- first_value = value;
- second_value = old_value;
- }
- char* cur_loc = storage;
- memcpy(cur_loc, key.data(), key.size());
- cur_loc += key.size();
- *cur_loc = ':';
- ++cur_loc;
- *cur_loc = ' ';
- ++cur_loc;
- memcpy(cur_loc, first_value.data(), first_value.size());
- cur_loc += first_value.size();
- *cur_loc = ',';
- ++cur_loc;
- memcpy(cur_loc, second_value.data(), second_value.size());
-
- *d = HeaderLineDescription(base_idx,
- base_idx + key.size(),
- base_idx + key.size() + 2,
- base_idx + new_size,
- block_buffer_idx);
-}
-
-// Removes all keys value pairs with key 'key' starting at 'start'.
-void BalsaHeaders::RemoveAllOfHeaderStartingAt(const base::StringPiece& key,
- HeaderLines::iterator start) {
- while (start != header_lines_.end()) {
- start->skip = true;
- ++start;
- start = GetHeaderLinesIterator(key, start);
- }
-}
-
-void BalsaHeaders::HackHeader(const base::StringPiece& key,
- const base::StringPiece& value) {
- // See TODO in balsa_headers.h
- const HeaderLines::iterator end = header_lines_.end();
- const HeaderLines::iterator begin = header_lines_.begin();
- HeaderLines::iterator i = GetHeaderLinesIteratorNoSkip(key, begin);
- if (i != end) {
- // First, remove all of the header lines including this one. We want to
- // remove before replacing, in case our replacement ends up being appended
- // at the end (and thus would be removed by this call)
- RemoveAllOfHeaderStartingAt(key, i);
- // Now add the replacement, at this location.
- AddAndMakeDescription(key, value, &(*i));
- return;
- }
- AppendHeader(key, value);
-}
-
-void BalsaHeaders::HackAppendToHeader(const base::StringPiece& key,
- const base::StringPiece& append_value) {
- // See TODO in balsa_headers.h
- const HeaderLines::iterator end = header_lines_.end();
- const HeaderLines::iterator begin = header_lines_.begin();
-
- HeaderLines::iterator i = GetHeaderLinesIterator(key, begin);
- if (i == end) {
- HackHeader(key, append_value);
- return;
- }
-
- AppendOrPrependAndMakeDescription(key, append_value, true, &(*i));
-}
-
-void BalsaHeaders::ReplaceOrAppendHeader(const base::StringPiece& key,
- const base::StringPiece& value) {
- const HeaderLines::iterator end = header_lines_.end();
- const HeaderLines::iterator begin = header_lines_.begin();
- HeaderLines::iterator i = GetHeaderLinesIterator(key, begin);
- if (i != end) {
- // First, remove all of the header lines including this one. We want to
- // remove before replacing, in case our replacement ends up being appended
- // at the end (and thus would be removed by this call)
- RemoveAllOfHeaderStartingAt(key, i);
- // Now, take the first instance and replace it. This will remove the
- // 'skipped' tag if the replacement is done in-place.
- AddAndMakeDescription(key, value, &(*i));
- return;
- }
- AppendHeader(key, value);
-}
-
-void BalsaHeaders::AppendHeader(const base::StringPiece& key,
- const base::StringPiece& value) {
- HeaderLineDescription hld;
- AddAndMakeDescription(key, value, &hld);
- header_lines_.push_back(hld);
-}
-
-void BalsaHeaders::AppendToHeader(const base::StringPiece& key,
- const base::StringPiece& value) {
- AppendOrPrependToHeader(key, value, true);
-}
-
-void BalsaHeaders::PrependToHeader(const base::StringPiece& key,
- const base::StringPiece& value) {
- AppendOrPrependToHeader(key, value, false);
-}
-
-base::StringPiece BalsaHeaders::GetValueFromHeaderLineDescription(
- const HeaderLineDescription& line) const {
- DCHECK_GE(line.last_char_idx, line.value_begin_idx);
- return base::StringPiece(GetPtr(line.buffer_base_idx) + line.value_begin_idx,
- line.last_char_idx - line.value_begin_idx);
-}
-
-const base::StringPiece BalsaHeaders::GetHeader(
- const base::StringPiece& key) const {
- DCHECK(!IsMultivaluedHeader(key))
- << "Header '" << key << "' may consist of multiple lines. Do not "
- << "use BalsaHeaders::GetHeader() or you may be missing some of its "
- << "values.";
- const HeaderLines::const_iterator end = header_lines_.end();
- const HeaderLines::const_iterator begin = header_lines_.begin();
- HeaderLines::const_iterator i = GetConstHeaderLinesIterator(key, begin);
- if (i == end) {
- return base::StringPiece(NULL, 0);
- }
- return GetValueFromHeaderLineDescription(*i);
-}
-
-BalsaHeaders::const_header_lines_iterator BalsaHeaders::GetHeaderPosition(
- const base::StringPiece& key) const {
- const HeaderLines::const_iterator end = header_lines_.end();
- const HeaderLines::const_iterator begin = header_lines_.begin();
- HeaderLines::const_iterator i = GetConstHeaderLinesIterator(key, begin);
- if (i == end) {
- return header_lines_end();
- }
-
- return const_header_lines_iterator(this, (i - begin));
-}
-
-BalsaHeaders::const_header_lines_key_iterator BalsaHeaders::GetIteratorForKey(
- const base::StringPiece& key) const {
- HeaderLines::const_iterator i =
- GetConstHeaderLinesIterator(key, header_lines_.begin());
- if (i == header_lines_.end()) {
- return header_lines_key_end();
- }
-
- const HeaderLines::const_iterator begin = header_lines_.begin();
- return const_header_lines_key_iterator(this, (i - begin), key);
-}
-
-void BalsaHeaders::AppendOrPrependToHeader(const base::StringPiece& key,
- const base::StringPiece& value,
- bool append) {
- HeaderLines::iterator i = GetHeaderLinesIterator(key, header_lines_.begin());
- if (i == header_lines_.end()) {
- // The header did not exist already. Instead of appending to an existing
- // header simply append the key/value pair to the headers.
- AppendHeader(key, value);
- return;
- }
- HeaderLineDescription hld = *i;
-
- AppendOrPrependAndMakeDescription(key, value, append, &hld);
-
- // Invalidate the old header line and add the new one.
- i->skip = true;
- header_lines_.push_back(hld);
-}
-
-BalsaHeaders::HeaderLines::const_iterator
-BalsaHeaders::GetConstHeaderLinesIterator(
- const base::StringPiece& key,
- BalsaHeaders::HeaderLines::const_iterator start) const {
- const HeaderLines::const_iterator end = header_lines_.end();
- for (HeaderLines::const_iterator i = start; i != end; ++i) {
- const HeaderLineDescription& line = *i;
- if (line.skip) {
- continue;
- }
- const size_t key_len = line.key_end_idx - line.first_char_idx;
-
- if (key_len != key.size()) {
- continue;
- }
- if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
- key.data(), key_len) == 0) {
- DCHECK_GE(line.last_char_idx, line.value_begin_idx);
- return i;
- }
- }
- return end;
-}
-
-BalsaHeaders::HeaderLines::iterator BalsaHeaders::GetHeaderLinesIteratorNoSkip(
- const base::StringPiece& key,
- BalsaHeaders::HeaderLines::iterator start) {
- const HeaderLines::iterator end = header_lines_.end();
- for (HeaderLines::iterator i = start; i != end; ++i) {
- const HeaderLineDescription& line = *i;
- const size_t key_len = line.key_end_idx - line.first_char_idx;
-
- if (key_len != key.size()) {
- continue;
- }
- if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
- key.data(), key_len) == 0) {
- DCHECK_GE(line.last_char_idx, line.value_begin_idx);
- return i;
- }
- }
- return end;
-}
-
-BalsaHeaders::HeaderLines::iterator BalsaHeaders::GetHeaderLinesIterator(
- const base::StringPiece& key,
- BalsaHeaders::HeaderLines::iterator start) {
- const HeaderLines::iterator end = header_lines_.end();
- for (HeaderLines::iterator i = start; i != end; ++i) {
- const HeaderLineDescription& line = *i;
- if (line.skip) {
- continue;
- }
- const size_t key_len = line.key_end_idx - line.first_char_idx;
-
- if (key_len != key.size()) {
- continue;
- }
- if (strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
- key.data(), key_len) == 0) {
- DCHECK_GE(line.last_char_idx, line.value_begin_idx);
- return i;
- }
- }
- return end;
-}
-
-void BalsaHeaders::GetAllOfHeader(
- const base::StringPiece& key, std::vector<base::StringPiece>* out) const {
- for (const_header_lines_key_iterator it = GetIteratorForKey(key);
- it != header_lines_end(); ++it) {
- out->push_back(it->second);
- }
-}
-
-bool BalsaHeaders::HasNonEmptyHeader(const base::StringPiece& key) const {
- for (const_header_lines_key_iterator it = GetIteratorForKey(key);
- it != header_lines_key_end(); ++it) {
- if (!it->second.empty())
- return true;
- }
- return false;
-}
-
-void BalsaHeaders::GetAllOfHeaderAsString(const base::StringPiece& key,
- std::string* out) const {
- const_header_lines_iterator it = header_lines_begin();
- const_header_lines_iterator end = header_lines_end();
-
- for (; it != end; ++it) {
- if (key == it->first) {
- if (!out->empty()) {
- out->append(",");
- }
- out->append(std::string(it->second.data(), it->second.size()));
- }
- }
-}
-
-// static
-bool BalsaHeaders::IsMultivaluedHeader(const base::StringPiece& header) {
- return g_multivalued_headers.find(header) != g_multivalued_headers.end();
-}
-
-void BalsaHeaders::RemoveAllOfHeader(const base::StringPiece& key) {
- HeaderLines::iterator it = GetHeaderLinesIterator(key, header_lines_.begin());
- RemoveAllOfHeaderStartingAt(key, it);
-}
-
-void BalsaHeaders::RemoveAllHeadersWithPrefix(const base::StringPiece& key) {
- for (HeaderLines::size_type i = 0; i < header_lines_.size(); ++i) {
- if (header_lines_[i].skip) {
- continue;
- }
- HeaderLineDescription& line = header_lines_[i];
- const size_t key_len = line.key_end_idx - line.first_char_idx;
- if (key_len < key.size()) {
- // If the key given to us is longer than this header, don't consider it.
- continue;
- }
- if (!strncasecmp(GetPtr(line.buffer_base_idx) + line.first_char_idx,
- key.data(), key.size())) {
- line.skip = true;
- }
- }
-}
-
-size_t BalsaHeaders::GetMemoryUsedLowerBound() const {
- return (sizeof(*this) +
- balsa_buffer_.GetTotalBufferBlockSize() +
- header_lines_.capacity() * sizeof(HeaderLineDescription));
-}
-
-size_t BalsaHeaders::GetSizeForWriteBuffer() const {
- // First add the space required for the first line + CRLF
- size_t write_buf_size = whitespace_4_idx_ - non_whitespace_1_idx_ + 2;
- // Then add the space needed for each header line to write out + CRLF.
- const HeaderLines::size_type end = header_lines_.size();
- for (HeaderLines::size_type i = 0; i < end; ++i) {
- const HeaderLineDescription& line = header_lines_[i];
- if (!line.skip) {
- // Add the key size and ": ".
- write_buf_size += line.key_end_idx - line.first_char_idx + 2;
- // Add the value size and the CRLF
- write_buf_size += line.last_char_idx - line.value_begin_idx + 2;
- }
- }
- // Finally tag on the terminal CRLF.
- return write_buf_size + 2;
-}
-
-void BalsaHeaders::DumpToString(std::string* str) const {
- const base::StringPiece firstline = first_line();
- const int buffer_length =
- OriginalHeaderStreamEnd() - OriginalHeaderStreamBegin();
- // First check whether the header object is empty.
- if (firstline.empty() && buffer_length == 0) {
- str->append("\n<empty header>\n");
- return;
- }
-
- // Then check whether the header is in a partially parsed state. If so, just
- // dump the raw data.
- if (balsa_buffer_.can_write_to_contiguous_buffer()) {
- base::StringAppendF(str, "\n<incomplete header len: %d>\n%.*s\n",
- buffer_length, buffer_length,
- OriginalHeaderStreamBegin());
- return;
- }
-
- // If the header is complete, then just dump them with the logical key value
- // pair.
- str->reserve(str->size() + GetSizeForWriteBuffer());
- base::StringAppendF(str, "\n %.*s\n",
- static_cast<int>(firstline.size()),
- firstline.data());
- BalsaHeaders::const_header_lines_iterator i = header_lines_begin();
- for (; i != header_lines_end(); ++i) {
- base::StringAppendF(str, " %.*s: %.*s\n",
- static_cast<int>(i->first.size()), i->first.data(),
- static_cast<int>(i->second.size()), i->second.data());
- }
-}
-
-void BalsaHeaders::SetFirstLine(const base::StringPiece& line) {
- base::StringPiece new_line = balsa_buffer_.Write(line,
- &firstline_buffer_base_idx_);
- whitespace_1_idx_ = new_line.data() - GetPtr(firstline_buffer_base_idx_);
- non_whitespace_1_idx_ = whitespace_1_idx_;
- whitespace_4_idx_ = whitespace_1_idx_ + line.size();
- whitespace_2_idx_ = whitespace_4_idx_;
- non_whitespace_2_idx_ = whitespace_4_idx_;
- whitespace_3_idx_ = whitespace_4_idx_;
- non_whitespace_3_idx_ = whitespace_4_idx_;
- end_of_firstline_idx_ = whitespace_4_idx_;
-}
-
-void BalsaHeaders::SetContentLength(size_t length) {
- // If the content-length is already the one we want, don't do anything.
- if (content_length_status_ == BalsaHeadersEnums::VALID_CONTENT_LENGTH &&
- content_length_ == length) {
- return;
- }
- const base::StringPiece content_length(kContentLength,
- sizeof(kContentLength) - 1);
- // If header state indicates that there is either a content length or
- // transfer encoding header, remove them before adding the new content
- // length. There is always the possibility that client can manually add
- // either header directly and cause content_length_status_ or
- // transfer_encoding_is_chunked_ to be inconsistent with the actual header.
- // In the interest of efficiency, however, we will assume that clients will
- // use the header object correctly and thus we will not scan the all headers
- // each time this function is called.
- if (content_length_status_ != BalsaHeadersEnums::NO_CONTENT_LENGTH) {
- RemoveAllOfHeader(content_length);
- } else if (transfer_encoding_is_chunked_) {
- const base::StringPiece transfer_encoding(kTransferEncoding,
- sizeof(kTransferEncoding) - 1);
- RemoveAllOfHeader(transfer_encoding);
- transfer_encoding_is_chunked_ = false;
- }
- content_length_status_ = BalsaHeadersEnums::VALID_CONTENT_LENGTH;
- content_length_ = length;
- // FastUInt64ToBuffer is supposed to use a maximum of kFastToBufferSize bytes.
- char buffer[kFastToBufferSize];
- int len_converted = snprintf(buffer, sizeof(buffer), "%zd", length);
- CHECK_GT(len_converted, 0);
- const base::StringPiece length_str(buffer, len_converted);
- AppendHeader(content_length, length_str);
-}
-
-void BalsaHeaders::SetChunkEncoding(bool chunk_encode) {
- if (transfer_encoding_is_chunked_ == chunk_encode) {
- return;
- }
- if (content_length_status_ != BalsaHeadersEnums::NO_CONTENT_LENGTH &&
- chunk_encode) {
- // Want to change to chunk encoding, but have content length. Arguably we
- // can leave this step out, since transfer-encoding overrides
- // content-length.
- const base::StringPiece content_length(kContentLength,
- sizeof(kContentLength) - 1);
- RemoveAllOfHeader(content_length);
- content_length_status_ = BalsaHeadersEnums::NO_CONTENT_LENGTH;
- content_length_ = 0;
- }
- const base::StringPiece transfer_encoding(kTransferEncoding,
- sizeof(kTransferEncoding) - 1);
- if (chunk_encode) {
- const char kChunked[] = "chunked";
- const base::StringPiece chunked(kChunked, sizeof(kChunked) - 1);
- AppendHeader(transfer_encoding, chunked);
- } else {
- RemoveAllOfHeader(transfer_encoding);
- }
- transfer_encoding_is_chunked_ = chunk_encode;
-}
-
-// See the comment about this function in the header file for a
-// warning about its usage.
-void BalsaHeaders::SetFirstlineFromStringPieces(
- const base::StringPiece& firstline_a,
- const base::StringPiece& firstline_b,
- const base::StringPiece& firstline_c) {
- size_t line_size = (firstline_a.size() +
- firstline_b.size() +
- firstline_c.size() +
- 2);
- char* storage = balsa_buffer_.Reserve(line_size, &firstline_buffer_base_idx_);
- char* cur_loc = storage;
-
- memcpy(cur_loc, firstline_a.data(), firstline_a.size());
- cur_loc += firstline_a.size();
-
- *cur_loc = ' ';
- ++cur_loc;
-
- memcpy(cur_loc, firstline_b.data(), firstline_b.size());
- cur_loc += firstline_b.size();
-
- *cur_loc = ' ';
- ++cur_loc;
-
- memcpy(cur_loc, firstline_c.data(), firstline_c.size());
-
- whitespace_1_idx_ = storage - GetPtr(firstline_buffer_base_idx_);
- non_whitespace_1_idx_ = whitespace_1_idx_;
- whitespace_2_idx_ = non_whitespace_1_idx_ + firstline_a.size();
- non_whitespace_2_idx_ = whitespace_2_idx_ + 1;
- whitespace_3_idx_ = non_whitespace_2_idx_ + firstline_b.size();
- non_whitespace_3_idx_ = whitespace_3_idx_ + 1;
- whitespace_4_idx_ = non_whitespace_3_idx_ + firstline_c.size();
- end_of_firstline_idx_ = whitespace_4_idx_;
-}
-
-void BalsaHeaders::SetRequestMethod(const base::StringPiece& method) {
- // This is the first of the three parts of the firstline.
- if (method.size() <= (whitespace_2_idx_ - non_whitespace_1_idx_)) {
- non_whitespace_1_idx_ = whitespace_2_idx_ - method.size();
- char* stream_begin = GetPtr(firstline_buffer_base_idx_);
- memcpy(stream_begin + non_whitespace_1_idx_,
- method.data(),
- method.size());
- } else {
- // The new method is too large to fit in the space available for the old
- // one, so we have to reformat the firstline.
- SetFirstlineFromStringPieces(method, request_uri(), request_version());
- }
-}
-
-void BalsaHeaders::SetResponseVersion(const base::StringPiece& version) {
- // Note: There is no difference between request_method() and
- // response_Version(). Thus, a function to set one is equivalent to a
- // function to set the other. We maintain two functions for this as it is
- // much more descriptive, and makes code more understandable.
- SetRequestMethod(version);
-}
-
-void BalsaHeaders::SetRequestUri(const base::StringPiece& uri) {
- SetFirstlineFromStringPieces(request_method(), uri, request_version());
-}
-
-void BalsaHeaders::SetResponseCode(const base::StringPiece& code) {
- // Note: There is no difference between request_uri() and response_code().
- // Thus, a function to set one is equivalent to a function to set the other.
- // We maintain two functions for this as it is much more descriptive, and
- // makes code more understandable.
- SetRequestUri(code);
-}
-
-void BalsaHeaders::SetParsedResponseCodeAndUpdateFirstline(
- size_t parsed_response_code) {
- char buffer[kFastToBufferSize];
- int len_converted = snprintf(buffer, sizeof(buffer),
- "%zd", parsed_response_code);
- CHECK_GT(len_converted, 0);
- SetResponseCode(base::StringPiece(buffer, len_converted));
-}
-
-void BalsaHeaders::SetRequestVersion(const base::StringPiece& version) {
- // This is the last of the three parts of the firstline.
- // Since whitespace_3_idx and non_whitespace_3_idx may point to the same
- // place, we ensure below that any available space includes space for a
- // litteral space (' ') character between the second component and the third
- // component. If the space between whitespace_3_idx_ and
- // end_of_firstline_idx_ is >= to version.size() + 1 (for the space), then we
- // can update the firstline in-place.
- char* stream_begin = GetPtr(firstline_buffer_base_idx_);
- if (version.size() + 1 <= end_of_firstline_idx_ - whitespace_3_idx_) {
- *(stream_begin + whitespace_3_idx_) = kSpaceChar;
- non_whitespace_3_idx_ = whitespace_3_idx_ + 1;
- whitespace_4_idx_ = non_whitespace_3_idx_ + version.size();
- memcpy(stream_begin + non_whitespace_3_idx_,
- version.data(),
- version.size());
- } else {
- // The new version is to large to fit in the space available for the old
- // one, so we have to reformat the firstline.
- SetFirstlineFromStringPieces(request_method(), request_uri(), version);
- }
-}
-
-void BalsaHeaders::SetResponseReasonPhrase(const base::StringPiece& reason) {
- // Note: There is no difference between request_version() and
- // response_reason_phrase(). Thus, a function to set one is equivalent to a
- // function to set the other. We maintain two functions for this as it is
- // much more descriptive, and makes code more understandable.
- SetRequestVersion(reason);
-}
-
-} // namespace net
diff --git a/net/tools/flip_server/balsa_headers.h b/net/tools/flip_server/balsa_headers.h
deleted file mode 100644
index 2c8b083..0000000
--- a/net/tools/flip_server/balsa_headers.h
+++ /dev/null
@@ -1,1138 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_H_
-#define NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_H_
-
-#include <algorithm>
-#include <iosfwd>
-#include <iterator>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/port.h"
-#include "base/strings/string_piece.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "net/tools/flip_server/string_piece_utils.h"
-
-namespace net {
-
-// WARNING:
-// Note that -no- char* returned by any function in this
-// file is null-terminated.
-
-// This class exists to service the specific needs of BalsaHeaders.
-//
-// Functional goals:
-// 1) provide a backing-store for all of the StringPieces that BalsaHeaders
-// returns. Every StringPiece returned from BalsaHeaders should remain
-// valid until the BalsaHeader's object is cleared, or the header-line is
-// erased.
-// 2) provide a backing-store for BalsaFrame, which requires contiguous memory
-// for its fast-path parsing functions. Note that the cost of copying is
-// less than the cost of requiring the parser to do slow-path parsing, as
-// it would have to check for bounds every byte, instead of every 16 bytes.
-//
-// This class is optimized for the case where headers are stored in one of two
-// buffers. It doesn't make a lot of effort to densely pack memory-- in fact,
-// it -may- be somewhat memory inefficient. This possible inefficiency allows a
-// certain simplicity of implementation and speed which makes it worthwhile.
-// If, in the future, better memory density is required, it should be possible
-// to reuse the abstraction presented by this object to achieve those goals.
-//
-// In the most common use-case, this memory inefficiency should be relatively
-// small.
-//
-// Alternate implementations of BalsaBuffer may include:
-// - vector of strings, one per header line (similar to HTTPHeaders)
-// - densely packed strings:
-// - keep a sorted array/map of free-space linked lists or numbers.
-// - use the entry that most closely first your needs.
-// - at this point, perhaps just use a vector of strings, and let
-// the allocator do the right thing.
-//
-class BalsaBuffer {
- public:
- static const size_t kDefaultBlocksize = 4096;
- // We have two friends here. These exist as friends as we
- // want to allow access to the constructors for the test
- // class and the Balsa* classes. We put this into the
- // header file as we want this class to be inlined into the
- // BalsaHeaders implementation, yet be testable.
- friend class BalsaBufferTestSpouse;
- friend class BalsaHeaders;
- friend class BalsaBufferTest;
-
- // The BufferBlock is a structure used internally by the
- // BalsaBuffer class to store the base buffer pointers to
- // each block, as well as the important metadata for buffer
- // sizes and bytes free.
- struct BufferBlock {
- public:
- char* buffer;
- size_t buffer_size;
- size_t bytes_free;
-
- size_t bytes_used() const {
- return buffer_size - bytes_free;
- }
- char* start_of_unused_bytes() const {
- return buffer + bytes_used();
- }
-
- BufferBlock() : buffer(NULL), buffer_size(0), bytes_free(0) {}
- ~BufferBlock() {}
-
- BufferBlock(char* buf, size_t size, size_t free) :
- buffer(buf), buffer_size(size), bytes_free(free) {}
- // Yes we want this to be copyable (it gets stuck into vectors).
- // For this reason, we don't use scoped ptrs, etc. here-- it
- // is more efficient to manage this memory externally to this
- // object.
- };
-
- typedef std::vector<BufferBlock> Blocks;
-
- ~BalsaBuffer();
-
- // Returns the total amount of memory used by the buffer blocks.
- size_t GetTotalBufferBlockSize() const;
-
- const char* GetPtr(Blocks::size_type block_idx) const {
- DCHECK_LT(block_idx, blocks_.size())
- << block_idx << ", " << blocks_.size();
- return blocks_[block_idx].buffer;
- }
-
- char* GetPtr(Blocks::size_type block_idx) {
- DCHECK_LT(block_idx, blocks_.size())
- << block_idx << ", " << blocks_.size();
- return blocks_[block_idx].buffer;
- }
-
- // This function is different from Write(), as it ensures that the data
- // stored via subsequent calls to this function are all contiguous (and in
- // the order in which these writes happened). This is essentially the same
- // as a string append.
- //
- // You may call this function at any time between object
- // construction/Clear(), and the calling of the
- // NoMoreWriteToContiguousBuffer() function.
- //
- // You must not call this function after the NoMoreWriteToContiguousBuffer()
- // function is called, unless a Clear() has been called since.
- // If you do, the program will abort().
- //
- // This condition is placed upon this code so that calls to Write() can
- // append to the buffer in the first block safely, and without invaliding
- // the StringPiece which it returns.
- //
- // This function's main intended user is the BalsaFrame class, which,
- // for reasons of efficiency, requires that the buffer from which it parses
- // the headers be contiguous.
- //
- void WriteToContiguousBuffer(const base::StringPiece& sp);
-
- void NoMoreWriteToContiguousBuffer() {
- can_write_to_contiguous_buffer_ = false;
- }
-
- // Takes a StringPiece and writes it to "permanent" storage, then returns a
- // StringPiece which points to that data. If block_idx != NULL, it will be
- // assigned the index of the block into which the data was stored.
- // Note that the 'permanent' storage in which it stores data may be in
- // the first block IFF the NoMoreWriteToContiguousBuffer function has
- // been called since the last Clear/Construction.
- base::StringPiece Write(const base::StringPiece& sp,
- Blocks::size_type* block_buffer_idx);
-
- // Reserves "permanent" storage of the size indicated. Returns a pointer to
- // the beginning of that storage, and assigns the index of the block used to
- // block_buffer_idx. This function uses the first block IFF the
- // NoMoreWriteToContiguousBuffer function has been called since the last
- // Clear/Construction.
- char* Reserve(size_t size, Blocks::size_type* block_buffer_idx);
-
- void Clear();
-
- void Swap(BalsaBuffer* b);
-
- void CopyFrom(const BalsaBuffer& b);
-
- const char* StartOfFirstBlock() const {
- return blocks_[0].buffer;
- }
-
- const char* EndOfFirstBlock() const {
- return blocks_[0].buffer + blocks_[0].bytes_used();
- }
-
- bool can_write_to_contiguous_buffer() const {
- return can_write_to_contiguous_buffer_;
- }
- size_t blocksize() const { return blocksize_; }
- Blocks::size_type num_blocks() const { return blocks_.size(); }
- size_t buffer_size(size_t idx) const { return blocks_[idx].buffer_size; }
- size_t bytes_used(size_t idx) const { return blocks_[idx].bytes_used(); }
-
- protected:
- BalsaBuffer();
-
- explicit BalsaBuffer(size_t blocksize);
-
- BufferBlock AllocBlock();
-
- BufferBlock AllocCustomBlock(size_t blocksize);
-
- BufferBlock CopyBlock(const BufferBlock& b);
-
- // Cleans up the object.
- // The block at start_idx, and all subsequent blocks
- // will be cleared and have associated memory deleted.
- void CleanupBlocksStartingFrom(Blocks::size_type start_idx);
-
- // A container of BufferBlocks
- Blocks blocks_;
-
- // The default allocation size for a block.
- // In general, blocksize_ bytes will be allocated for
- // each buffer.
- size_t blocksize_;
-
- // If set to true, then the first block cannot be used for Write() calls as
- // the WriteToContiguous... function will modify the base pointer for this
- // block, and the Write() calls need to be sure that the base pointer will
- // not be changing in order to provide the user with StringPieces which
- // continue to be valid.
- bool can_write_to_contiguous_buffer_;
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-// All of the functions in the BalsaHeaders class use string pieces, by either
-// using the StringPiece class, or giving an explicit size and char* (as these
-// are the native representation for these string pieces).
-// This is done for several reasons.
-// 1) This minimizes copying/allocation/deallocation as compared to using
-// string parameters
-// 2) This reduces the number of strlen() calls done (as the length of any
-// string passed in is relatively likely to be known at compile time, and for
-// those strings passed back we obviate the need for a strlen() to determine
-// the size of new storage allocations if a new allocation is required.
-// 3) This class attempts to store all of its data in two linear buffers in
-// order to enhance the speed of parsing and writing out to a buffer. As a
-// result, many string pieces are -not- terminated by '\0', and are not
-// c-strings. Since this is the case, we must delineate the length of the
-// string explicitly via a length.
-//
-// WARNING: The side effect of using StringPiece is that if the underlying
-// buffer changes (due to modifying the headers) the StringPieces which point
-// to the data which was modified, may now contain "garbage", and should not
-// be dereferenced.
-// For example, If you fetch some component of the first-line, (request or
-// response), and then you modify the first line, the StringPieces you
-// originally received from the original first-line may no longer be valid).
-//
-// StringPieces pointing to pieces of header lines which have not been
-// erased() or modified should be valid until the object is cleared or
-// destroyed.
-
-class BalsaHeaders {
- public:
- struct HeaderLineDescription {
- HeaderLineDescription(size_t first_character_index,
- size_t key_end_index,
- size_t value_begin_index,
- size_t last_character_index,
- size_t buffer_base_index) :
- first_char_idx(first_character_index),
- key_end_idx(key_end_index),
- value_begin_idx(value_begin_index),
- last_char_idx(last_character_index),
- buffer_base_idx(buffer_base_index),
- skip(false) {}
-
- HeaderLineDescription() :
- first_char_idx(0),
- key_end_idx(0),
- value_begin_idx(0),
- last_char_idx(0),
- buffer_base_idx(0),
- skip(false) {}
-
- size_t first_char_idx;
- size_t key_end_idx;
- size_t value_begin_idx;
- size_t last_char_idx;
- BalsaBuffer::Blocks::size_type buffer_base_idx;
- bool skip;
- };
-
- typedef std::vector<base::StringPiece> HeaderTokenList;
- friend bool ParseHTTPFirstLine(const char* begin,
- const char* end,
- bool is_request,
- size_t max_request_uri_length,
- BalsaHeaders* headers,
- BalsaFrameEnums::ErrorCode* error_code);
-
- protected:
- typedef std::vector<HeaderLineDescription> HeaderLines;
-
- // Why these base classes (iterator_base, reverse_iterator_base)? Well, if
- // we do want to export both iterator and const_iterator types (currently we
- // only have const_iterator), then this is useful to avoid code duplication.
- // Additionally, having this base class makes comparisons of iterators of
- // different types (they're different types to ensure that operator= and
- // constructors do not work in the places where they're expected to not work)
- // work properly. There could be as many as 4 iterator types, all based on
- // the same data as iterator_base... so it makes sense to simply have some
- // base classes.
-
- class iterator_base {
- public:
- friend class BalsaHeaders;
- friend class reverse_iterator_base;
- typedef std::pair<base::StringPiece, base::StringPiece> StringPiecePair;
- typedef StringPiecePair value_type;
- typedef value_type& reference;
- typedef value_type* pointer;
-
- typedef std::forward_iterator_tag iterator_category;
- typedef ptrdiff_t difference_type;
-
- typedef iterator_base self;
-
- // default constructor.
- iterator_base();
-
- // copy constructor.
- iterator_base(const iterator_base& it);
-
- reference operator*() const {
- return Lookup(idx_);
- }
-
- pointer operator->() const {
- return &(this->operator*());
- }
-
- bool operator==(const self& it) const {
- return idx_ == it.idx_;
- }
-
- bool operator<(const self& it) const {
- return idx_ < it.idx_;
- }
-
- bool operator<=(const self& it) const {
- return idx_ <= it.idx_;
- }
-
- bool operator!=(const self& it) const {
- return !(*this == it);
- }
-
- bool operator>(const self& it) const {
- return it < *this;
- }
-
- bool operator>=(const self& it) const {
- return it <= *this;
- }
-
- // This mainly exists so that we can have interesting output for
- // unittesting. The EXPECT_EQ, EXPECT_NE functions require that
- // operator<< work for the classes it sees. It would be better if there
- // was an additional traits-like system for the gUnit output... but oh
- // well.
- std::ostream& operator<<(std::ostream& os) const;
-
- protected:
- iterator_base(const BalsaHeaders* headers, HeaderLines::size_type index);
-
- void increment() {
- const HeaderLines& header_lines = headers_->header_lines_;
- const HeaderLines::size_type header_lines_size = header_lines.size();
- const HeaderLines::size_type original_idx = idx_;
- do {
- ++idx_;
- } while (idx_ < header_lines_size && header_lines[idx_].skip == true);
- // The condition below exists so that ++(end() - 1) == end(), even
- // if there are only 'skip == true' elements between the end() iterator
- // and the end of the vector of HeaderLineDescriptions.
- // TODO(fenix): refactor this list so that we don't have to do
- // linear scanning through skipped headers (and this condition is
- // then unnecessary)
- if (idx_ == header_lines_size) {
- idx_ = original_idx + 1;
- }
- }
-
- void decrement() {
- const HeaderLines& header_lines = headers_->header_lines_;
- const HeaderLines::size_type header_lines_size = header_lines.size();
- const HeaderLines::size_type original_idx = idx_;
- do {
- --idx_;
- } while (idx_ < header_lines_size && header_lines[idx_].skip == true);
- // The condition below exists so that --(rbegin() + 1) == rbegin(), even
- // if there are only 'skip == true' elements between the rbegin() iterator
- // and the beginning of the vector of HeaderLineDescriptions.
- // TODO(fenix): refactor this list so that we don't have to do
- // linear scanning through skipped headers (and this condition is
- // then unnecessary)
- if (idx_ > header_lines_size) {
- idx_ = original_idx - 1;
- }
- }
-
- reference Lookup(HeaderLines::size_type index) const {
- DCHECK_LT(index, headers_->header_lines_.size());
- const HeaderLineDescription& line = headers_->header_lines_[index];
- const char* stream_begin = headers_->GetPtr(line.buffer_base_idx);
- value_ = value_type(
- base::StringPiece(stream_begin + line.first_char_idx,
- line.key_end_idx - line.first_char_idx),
- base::StringPiece(stream_begin + line.value_begin_idx,
- line.last_char_idx - line.value_begin_idx));
- DCHECK_GE(line.key_end_idx, line.first_char_idx);
- DCHECK_GE(line.last_char_idx, line.value_begin_idx);
- return value_;
- }
-
- const BalsaHeaders* headers_;
- HeaderLines::size_type idx_;
- mutable StringPiecePair value_;
- };
-
- class reverse_iterator_base : public iterator_base {
- public:
- typedef reverse_iterator_base self;
- typedef iterator_base::reference reference;
- typedef iterator_base::pointer pointer;
- using iterator_base::headers_;
- using iterator_base::idx_;
-
- reverse_iterator_base() : iterator_base() {}
-
- // This constructor is no explicit purposely.
- reverse_iterator_base(const iterator_base& it) : // NOLINT
- iterator_base(it) {
- }
-
- self& operator=(const iterator_base& it) {
- idx_ = it.idx_;
- headers_ = it.headers_;
- return *this;
- }
-
- self& operator=(const reverse_iterator_base& it) {
- idx_ = it.idx_;
- headers_ = it.headers_;
- return *this;
- }
-
- reference operator*() const {
- return Lookup(idx_ - 1);
- }
-
- pointer operator->() const {
- return &(this->operator*());
- }
-
- reverse_iterator_base(const reverse_iterator_base& it) :
- iterator_base(it) { }
-
- protected:
- void increment() {
- --idx_;
- iterator_base::decrement();
- ++idx_;
- }
-
- void decrement() {
- ++idx_;
- iterator_base::increment();
- --idx_;
- }
-
- reverse_iterator_base(const BalsaHeaders* headers,
- HeaderLines::size_type index) :
- iterator_base(headers, index) {}
- };
-
- public:
- class const_header_lines_iterator : public iterator_base {
- friend class BalsaHeaders;
- public:
- typedef const_header_lines_iterator self;
- const_header_lines_iterator() : iterator_base() {}
-
- const_header_lines_iterator(const const_header_lines_iterator& it) :
- iterator_base(it.headers_, it.idx_) {}
-
- self& operator++() {
- iterator_base::increment();
- return *this;
- }
-
- self& operator--() {
- iterator_base::decrement();
- return *this;
- }
- protected:
- const_header_lines_iterator(const BalsaHeaders* headers,
- HeaderLines::size_type index) :
- iterator_base(headers, index) {}
- };
-
- class const_reverse_header_lines_iterator : public reverse_iterator_base {
- public:
- typedef const_reverse_header_lines_iterator self;
- const_reverse_header_lines_iterator() : reverse_iterator_base() {}
-
- const_reverse_header_lines_iterator(
- const const_header_lines_iterator& it) :
- reverse_iterator_base(it.headers_, it.idx_) {}
-
- const_reverse_header_lines_iterator(
- const const_reverse_header_lines_iterator& it) :
- reverse_iterator_base(it.headers_, it.idx_) {}
-
- const_header_lines_iterator base() {
- return const_header_lines_iterator(headers_, idx_);
- }
-
- self& operator++() {
- reverse_iterator_base::increment();
- return *this;
- }
-
- self& operator--() {
- reverse_iterator_base::decrement();
- return *this;
- }
- protected:
- const_reverse_header_lines_iterator(const BalsaHeaders* headers,
- HeaderLines::size_type index) :
- reverse_iterator_base(headers, index) {}
-
- friend class BalsaHeaders;
- };
-
- // An iterator that only stops at lines with a particular key.
- // See also GetIteratorForKey.
- //
- // Check against header_lines_key_end() to determine when iteration is
- // finished. header_lines_end() will also work.
- class const_header_lines_key_iterator : public iterator_base {
- friend class BalsaHeaders;
- public:
- typedef const_header_lines_key_iterator self;
- const_header_lines_key_iterator(const const_header_lines_key_iterator&);
-
- self& operator++() {
- do {
- iterator_base::increment();
- } while (!AtEnd() &&
- !StringPieceUtils::EqualIgnoreCase(key_, (**this).first));
- return *this;
- }
-
- void operator++(int ignore) {
- ++(*this);
- }
-
- // Only forward-iteration makes sense, so no operator-- defined.
-
- private:
- const_header_lines_key_iterator(const BalsaHeaders* headers,
- HeaderLines::size_type index,
- const base::StringPiece& key);
-
- // Should only be used for creating an end iterator.
- const_header_lines_key_iterator(const BalsaHeaders* headers,
- HeaderLines::size_type index);
-
- bool AtEnd() const {
- return *this >= headers_->header_lines_end();
- }
-
- base::StringPiece key_;
- };
-
- // TODO(fenix): Revisit the amount of bytes initially allocated to the second
- // block of the balsa_buffer_. It may make sense to pre-allocate some amount
- // (roughly the amount we'd append in new headers such as X-User-Ip, etc.)
- BalsaHeaders();
- ~BalsaHeaders();
-
- const_header_lines_iterator header_lines_begin() {
- return HeaderLinesBeginHelper<const_header_lines_iterator>();
- }
-
- const_header_lines_iterator header_lines_begin() const {
- return HeaderLinesBeginHelper<const_header_lines_iterator>();
- }
-
- const_header_lines_iterator header_lines_end() {
- return HeaderLinesEndHelper<const_header_lines_iterator>();
- }
-
- const_header_lines_iterator header_lines_end() const {
- return HeaderLinesEndHelper<const_header_lines_iterator>();
- }
-
- const_reverse_header_lines_iterator header_lines_rbegin() {
- return const_reverse_header_lines_iterator(header_lines_end());
- }
-
- const_reverse_header_lines_iterator header_lines_rbegin() const {
- return const_reverse_header_lines_iterator(header_lines_end());
- }
-
- const_reverse_header_lines_iterator header_lines_rend() {
- return const_reverse_header_lines_iterator(header_lines_begin());
- }
-
- const_reverse_header_lines_iterator header_lines_rend() const {
- return const_reverse_header_lines_iterator(header_lines_begin());
- }
-
- const_header_lines_key_iterator header_lines_key_end() const {
- return HeaderLinesEndHelper<const_header_lines_key_iterator>();
- }
-
- void erase(const const_header_lines_iterator& it) {
- DCHECK_EQ(it.headers_, this);
- DCHECK_LT(it.idx_, header_lines_.size());
- DCHECK_GE(it.idx_, 0u);
- header_lines_[it.idx_].skip = true;
- }
-
- void Clear();
-
- void Swap(BalsaHeaders* other);
-
- void CopyFrom(const BalsaHeaders& other);
-
- void HackHeader(const base::StringPiece& key, const base::StringPiece& value);
-
- // Same as AppendToHeader, except that it will attempt to preserve
- // header ordering.
- // Note that this will always append to an existing header, if available,
- // without moving the header around, or collapsing multiple header lines
- // with the same key together. For this reason, it only 'attempts' to
- // preserve header ordering.
- // TODO(fenix): remove this function and rename all occurances
- // of it in the code to AppendToHeader when the condition above
- // has been satisified.
- void HackAppendToHeader(const base::StringPiece& key,
- const base::StringPiece& value);
-
- // Replaces header entries with key 'key' if they exist, or appends
- // a new header if none exist. See 'AppendHeader' below for additional
- // comments about ContentLength and TransferEncoding headers. Note that this
- // will allocate new storage every time that it is called.
- // TODO(fenix): modify this function to reuse existing storage
- // if it is available.
- void ReplaceOrAppendHeader(const base::StringPiece& key,
- const base::StringPiece& value);
-
- // Append a new header entry to the header object. Clients who wish to append
- // Content-Length header should use SetContentLength() method instead of
- // adding the content length header using AppendHeader (manually adding the
- // content length header will not update the content_length_ and
- // content_length_status_ values).
- // Similarly, clients who wish to add or remove the transfer encoding header
- // in order to apply or remove chunked encoding should use SetChunkEncoding()
- // instead.
- void AppendHeader(const base::StringPiece& key,
- const base::StringPiece& value);
-
- // Appends ',value' to an existing header named 'key'. If no header with the
- // correct key exists, it will call AppendHeader(key, value). Calling this
- // function on a key which exists several times in the headers will produce
- // unpredictable results.
- void AppendToHeader(const base::StringPiece& key,
- const base::StringPiece& value);
-
- // Prepends 'value,' to an existing header named 'key'. If no header with the
- // correct key exists, it will call AppendHeader(key, value). Calling this
- // function on a key which exists several times in the headers will produce
- // unpredictable results.
- void PrependToHeader(const base::StringPiece& key,
- const base::StringPiece& value);
-
- const base::StringPiece GetHeader(const base::StringPiece& key) const;
-
- // Iterates over all currently valid header lines, appending their
- // values into the vector 'out', in top-to-bottom order.
- // Header-lines which have been erased are not currently valid, and
- // will not have their values appended. Empty values will be
- // represented as empty string. If 'key' doesn't exist in the headers at
- // all, out will not be changed. We do not clear the vector out
- // before adding new entries. If there are header lines with matching
- // key but empty value then they are also added to the vector out.
- // (Basically empty values are not treated in any special manner).
- //
- // Example:
- // Input header:
- // "GET / HTTP/1.0\r\n"
- // "key1: v1\r\n"
- // "key1: \r\n"
- // "key1:\r\n"
- // "key1: v1\r\n"
- // "key1:v2\r\n"
- //
- // vector out is initially: ["foo"]
- // vector out after GetAllOfHeader("key1", &out) is:
- // ["foo", "v1", "", "", "v2", "v1", "v2"]
-
- void GetAllOfHeader(const base::StringPiece& key,
- std::vector<base::StringPiece>* out) const;
-
- // Joins all values for key into a comma-separated string in out.
- // More efficient than calling JoinStrings on result of GetAllOfHeader if
- // you don't need the intermediate vector<StringPiece>.
- void GetAllOfHeaderAsString(const base::StringPiece& key,
- std::string* out) const;
-
- // Returns true if RFC 2616 Section 14 indicates that header can
- // have multiple values.
- static bool IsMultivaluedHeader(const base::StringPiece& header);
-
- // Determine if a given header is present.
- inline bool HasHeader(const base::StringPiece& key) const {
- return (GetConstHeaderLinesIterator(key, header_lines_.begin()) !=
- header_lines_.end());
- }
-
- // Returns true iff any header 'key' exists with non-empty value.
- bool HasNonEmptyHeader(const base::StringPiece& key) const;
-
- const_header_lines_iterator GetHeaderPosition(
- const base::StringPiece& key) const;
-
- // Returns a forward-only iterator that only stops at lines matching key.
- // String backing 'key' must remain valid for lifetime of iterator.
- //
- // Check returned iterator against header_lines_key_end() to determine when
- // iteration is finished.
- const_header_lines_key_iterator GetIteratorForKey(
- const base::StringPiece& key) const;
-
- void RemoveAllOfHeader(const base::StringPiece& key);
-
- // Removes all headers starting with 'key' [case insensitive]
- void RemoveAllHeadersWithPrefix(const base::StringPiece& key);
-
- // Returns the lower bound of memory used by this header object, including
- // all internal buffers and data structure. Some of the memory used cannot be
- // directly measure. For example, memory used for bookkeeping by standard
- // containers.
- size_t GetMemoryUsedLowerBound() const;
-
- // Returns the upper bound on the required buffer space to fully write out
- // the header object (this include the first line, all header lines, and the
- // final CRLF that marks the ending of the header).
- size_t GetSizeForWriteBuffer() const;
-
- // The following WriteHeader* methods are template member functions that
- // place one requirement on the Buffer class: it must implement a Write
- // method that takes a pointer and a length. The buffer passed in is not
- // required to be stretchable. For non-stretchable buffers, the user must
- // call GetSizeForWriteBuffer() to find out the upper bound on the output
- // buffer space required to make sure that the entire header is serialized.
- // BalsaHeaders will not check that there is adequate space in the buffer
- // object during the write.
-
- // Writes the entire header and the final CRLF that marks the end of the HTTP
- // header section to the buffer. After this method returns, no more header
- // data should be written to the buffer.
- template <typename Buffer>
- void WriteHeaderAndEndingToBuffer(Buffer* buffer) const {
- WriteToBuffer(buffer);
- WriteHeaderEndingToBuffer(buffer);
- }
-
- // Writes the final CRLF to the buffer to terminate the HTTP header section.
- // After this method returns, no more header data should be written to the
- // buffer.
- template <typename Buffer>
- static void WriteHeaderEndingToBuffer(Buffer* buffer) {
- buffer->Write("\r\n", 2);
- }
-
- // Writes the entire header to the buffer without the CRLF that terminates
- // the HTTP header. This lets users append additional header lines using
- // WriteHeaderLineToBuffer and then terminate the header with
- // WriteHeaderEndingToBuffer as the header is serialized to the
- // buffer, without having to first copy the header.
- template <typename Buffer>
- void WriteToBuffer(Buffer* buffer) const {
- // write the first line.
- const size_t firstline_len = whitespace_4_idx_ - non_whitespace_1_idx_;
- const char* stream_begin = GetPtr(firstline_buffer_base_idx_);
- buffer->Write(stream_begin + non_whitespace_1_idx_, firstline_len);
- buffer->Write("\r\n", 2);
- const HeaderLines::size_type end = header_lines_.size();
- for (HeaderLines::size_type i = 0; i < end; ++i) {
- const HeaderLineDescription& line = header_lines_[i];
- if (line.skip) {
- continue;
- }
- const char* line_ptr = GetPtr(line.buffer_base_idx);
- WriteHeaderLineToBuffer(
- buffer,
- base::StringPiece(line_ptr + line.first_char_idx,
- line.key_end_idx - line.first_char_idx),
- base::StringPiece(line_ptr + line.value_begin_idx,
- line.last_char_idx - line.value_begin_idx));
- }
- }
-
- // Takes a header line in the form of a key/value pair and append it to the
- // buffer. This function should be called after WriteToBuffer to
- // append additional header lines to the header without copying the header.
- // When the user is done with appending to the buffer,
- // WriteHeaderEndingToBuffer must be used to terminate the HTTP
- // header in the buffer. This method is a no-op if key is empty.
- template <typename Buffer>
- static void WriteHeaderLineToBuffer(Buffer* buffer,
- const base::StringPiece& key,
- const base::StringPiece& value) {
- // if the key is empty, we don't want to write the rest because it
- // will not be a well-formed header line.
- if (!key.empty()) {
- buffer->Write(key.data(), key.size());
- buffer->Write(": ", 2);
- buffer->Write(value.data(), value.size());
- buffer->Write("\r\n", 2);
- }
- }
-
- // Dump the textural representation of the header object to a string, which
- // is suitable for writing out to logs. All CRLF will be printed out as \n.
- // This function can be called on a header object in any state. Raw header
- // data will be printed out if the header object is not completely parsed,
- // e.g., when there was an error in the middle of parsing.
- // The header content is appended to the string; the original content is not
- // cleared.
- void DumpToString(std::string* str) const;
-
- const base::StringPiece first_line() const {
- DCHECK_GE(whitespace_4_idx_, non_whitespace_1_idx_);
- return base::StringPiece(BeginningOfFirstLine() + non_whitespace_1_idx_,
- whitespace_4_idx_ - non_whitespace_1_idx_);
- }
-
- // Returns the parsed value of the response code if it has been parsed.
- // Guaranteed to return 0 when unparsed (though it is a much better idea to
- // verify that the BalsaFrame had no errors while parsing).
- // This may return response codes which are outside the normal bounds of
- // HTTP response codes-- it is up to the user of this class to ensure that
- // the response code is one which is interpretable.
- size_t parsed_response_code() const { return parsed_response_code_; }
-
- const base::StringPiece request_method() const {
- DCHECK_GE(whitespace_2_idx_, non_whitespace_1_idx_);
- return base::StringPiece(BeginningOfFirstLine() + non_whitespace_1_idx_,
- whitespace_2_idx_ - non_whitespace_1_idx_);
- }
-
- const base::StringPiece response_version() const {
- // Note: There is no difference between request_method() and
- // response_version(). They both could be called
- // GetFirstTokenFromFirstline()... but that wouldn't be anywhere near as
- // descriptive.
- return request_method();
- }
-
- const base::StringPiece request_uri() const {
- DCHECK_GE(whitespace_3_idx_, non_whitespace_2_idx_);
- return base::StringPiece(BeginningOfFirstLine() + non_whitespace_2_idx_,
- whitespace_3_idx_ - non_whitespace_2_idx_);
- }
-
- const base::StringPiece response_code() const {
- // Note: There is no difference between request_uri() and response_code().
- // They both could be called GetSecondtTokenFromFirstline(), but, as noted
- // in an earlier comment, that wouldn't be as descriptive.
- return request_uri();
- }
-
- const base::StringPiece request_version() const {
- DCHECK_GE(whitespace_4_idx_, non_whitespace_3_idx_);
- return base::StringPiece(BeginningOfFirstLine() + non_whitespace_3_idx_,
- whitespace_4_idx_ - non_whitespace_3_idx_);
- }
-
- const base::StringPiece response_reason_phrase() const {
- // Note: There is no difference between request_version() and
- // response_reason_phrase(). They both could be called
- // GetThirdTokenFromFirstline(), but, as noted in an earlier comment, that
- // wouldn't be as descriptive.
- return request_version();
- }
-
- // Note that SetFirstLine will not update the internal indices for the
- // various bits of the first-line (and may set them all to zero).
- // If you'd like to use the accessors for the various bits of the firstline,
- // then you should use the Set* functions, or SetFirstlineFromStringPieces,
- // below, instead.
- //
- void SetFirstlineFromStringPieces(const base::StringPiece& firstline_a,
- const base::StringPiece& firstline_b,
- const base::StringPiece& firstline_c);
-
- void SetRequestFirstlineFromStringPieces(const base::StringPiece& method,
- const base::StringPiece& uri,
- const base::StringPiece& version) {
- SetFirstlineFromStringPieces(method, uri, version);
- }
-
- void SetResponseFirstlineFromStringPieces(
- const base::StringPiece& version,
- const base::StringPiece& code,
- const base::StringPiece& reason_phrase) {
- SetFirstlineFromStringPieces(version, code, reason_phrase);
- }
-
- // These functions are exactly the same, except that their names are
- // different. This is done so that the code using this class is more
- // expressive.
- void SetRequestMethod(const base::StringPiece& method);
- void SetResponseVersion(const base::StringPiece& version);
-
- void SetRequestUri(const base::StringPiece& uri);
- void SetResponseCode(const base::StringPiece& code);
- void set_parsed_response_code(size_t parsed_response_code) {
- parsed_response_code_ = parsed_response_code;
- }
- void SetParsedResponseCodeAndUpdateFirstline(size_t parsed_response_code);
-
- // These functions are exactly the same, except that their names are
- // different. This is done so that the code using this class is more
- // expressive.
- void SetRequestVersion(const base::StringPiece& version);
- void SetResponseReasonPhrase(const base::StringPiece& reason_phrase);
-
- // The biggest problem with SetFirstLine is that we don't want to use a
- // separate buffer for it. The second biggest problem with it is that the
- // first biggest problem requires that we store offsets into a buffer instead
- // of pointers into a buffer. Cuteness aside, SetFirstLine doesn't parse
- // the individual fields of the firstline, and so accessors to those fields
- // will not work properly after calling SetFirstLine. If you want those
- // accessors to work, use the Set* functions above this one.
- // SetFirstLine is stuff useful, however, if all you care about is correct
- // serialization with the rest of the header object.
- void SetFirstLine(const base::StringPiece& line);
-
- // Simple accessors to some of the internal state
- bool transfer_encoding_is_chunked() const {
- return transfer_encoding_is_chunked_;
- }
-
- static bool ResponseCodeImpliesNoBody(int code) {
- // From HTTP spec section 6.1.1 all 1xx responses must not have a body,
- // as well as 204 No Content and 304 Not Modified.
- return ((code >= 100) && (code <= 199)) || (code == 204) || (code == 304);
- }
-
- // Note: never check this for requests. Nothing bad will happen if you do,
- // but spec does not allow requests framed by connection close.
- // TODO(vitaliyl): refactor.
- bool is_framed_by_connection_close() const {
- // We declare that response is framed by connection close if it has no
- // content-length, no transfer encoding, and is allowed to have a body by
- // the HTTP spec.
- // parsed_response_code_ is 0 for requests, so ResponseCodeImpliesNoBody
- // will return false.
- return (content_length_status_ == BalsaHeadersEnums::NO_CONTENT_LENGTH) &&
- !transfer_encoding_is_chunked_ &&
- !ResponseCodeImpliesNoBody(parsed_response_code_);
- }
-
- size_t content_length() const { return content_length_; }
- BalsaHeadersEnums::ContentLengthStatus content_length_status() const {
- return content_length_status_;
- }
-
- // SetContentLength and SetChunkEncoding modifies the header object to use
- // content-length and transfer-encoding headers in a consistent manner. They
- // set all internal flags and status so client can get a consistent view from
- // various accessors.
- void SetContentLength(size_t length);
- void SetChunkEncoding(bool chunk_encode);
-
- protected:
- friend class BalsaFrame;
- friend class SpdyFrame;
- friend class HTTPMessage;
- friend class BalsaHeadersTokenUtils;
-
- const char* BeginningOfFirstLine() const {
- return GetPtr(firstline_buffer_base_idx_);
- }
-
- char* GetPtr(BalsaBuffer::Blocks::size_type block_idx) {
- return balsa_buffer_.GetPtr(block_idx);
- }
-
- const char* GetPtr(BalsaBuffer::Blocks::size_type block_idx) const {
- return balsa_buffer_.GetPtr(block_idx);
- }
-
- void WriteFromFramer(const char* ptr, size_t size) {
- balsa_buffer_.WriteToContiguousBuffer(base::StringPiece(ptr, size));
- }
-
- void DoneWritingFromFramer() {
- balsa_buffer_.NoMoreWriteToContiguousBuffer();
- }
-
- const char* OriginalHeaderStreamBegin() const {
- return balsa_buffer_.StartOfFirstBlock();
- }
-
- const char* OriginalHeaderStreamEnd() const {
- return balsa_buffer_.EndOfFirstBlock();
- }
-
- size_t GetReadableBytesFromHeaderStream() const {
- return OriginalHeaderStreamEnd() - OriginalHeaderStreamBegin();
- }
-
- void GetReadablePtrFromHeaderStream(const char** p, size_t* s) {
- *p = OriginalHeaderStreamBegin();
- *s = GetReadableBytesFromHeaderStream();
- }
-
- base::StringPiece GetValueFromHeaderLineDescription(
- const HeaderLineDescription& line) const;
-
- void AddAndMakeDescription(const base::StringPiece& key,
- const base::StringPiece& value,
- HeaderLineDescription* d);
-
- void AppendOrPrependAndMakeDescription(const base::StringPiece& key,
- const base::StringPiece& value,
- bool append,
- HeaderLineDescription* d);
-
- // Removes all header lines with the given key starting at start.
- void RemoveAllOfHeaderStartingAt(const base::StringPiece& key,
- HeaderLines::iterator start);
-
- // If the 'key' does not exist in the headers, calls
- // AppendHeader(key, value). Otherwise if append is true, appends ',value'
- // to the first existing header with key 'key'. If append is false, prepends
- // 'value,' to the first existing header with key 'key'.
- void AppendOrPrependToHeader(const base::StringPiece& key,
- const base::StringPiece& value,
- bool append);
-
- HeaderLines::const_iterator GetConstHeaderLinesIterator(
- const base::StringPiece& key,
- HeaderLines::const_iterator start) const;
-
- HeaderLines::iterator GetHeaderLinesIteratorNoSkip(
- const base::StringPiece& key,
- HeaderLines::iterator start);
-
- HeaderLines::iterator GetHeaderLinesIterator(
- const base::StringPiece& key,
- HeaderLines::iterator start);
-
- template <typename IteratorType>
- const IteratorType HeaderLinesBeginHelper() const {
- if (header_lines_.empty()) {
- return IteratorType(this, 0);
- }
- const HeaderLines::size_type header_lines_size = header_lines_.size();
- for (HeaderLines::size_type i = 0; i < header_lines_size; ++i) {
- if (header_lines_[i].skip == false) {
- return IteratorType(this, i);
- }
- }
- return IteratorType(this, 0);
- }
-
- template <typename IteratorType>
- const IteratorType HeaderLinesEndHelper() const {
- if (header_lines_.empty()) {
- return IteratorType(this, 0);
- }
- const HeaderLines::size_type header_lines_size = header_lines_.size();
- HeaderLines::size_type i = header_lines_size;
- do {
- --i;
- if (header_lines_[i].skip == false) {
- return IteratorType(this, i + 1);
- }
- } while (i != 0);
- return IteratorType(this, 0);
- }
-
- // At the moment, this function will always return the original headers.
- // In the future, it may not do so after erasing header lines, modifying
- // header lines, or modifying the first line.
- // For this reason, it is strongly suggested that use of this function is
- // only acceptable for the purpose of debugging parse errors seen by the
- // BalsaFrame class.
- base::StringPiece OriginalHeadersForDebugging() const {
- return base::StringPiece(OriginalHeaderStreamBegin(),
- OriginalHeaderStreamEnd() - OriginalHeaderStreamBegin());
- }
-
- BalsaBuffer balsa_buffer_;
-
- size_t content_length_;
- BalsaHeadersEnums::ContentLengthStatus content_length_status_;
- size_t parsed_response_code_;
- // HTTP firstlines all have the following structure:
- // LWS NONWS LWS NONWS LWS NONWS NOTCRLF CRLF
- // [\t \r\n]+ [^\t ]+ [\t ]+ [^\t ]+ [\t ]+ [^\t ]+ [^\r\n]+ "\r\n"
- // ws1 nws1 ws2 nws2 ws3 nws3 ws4
- // | [-------) [-------) [----------------)
- // REQ: method request_uri version
- // RESP: version statuscode reason
- //
- // The first NONWS->LWS component we'll call firstline_a.
- // The second firstline_b, and the third firstline_c.
- //
- // firstline_a goes from nws1 to (but not including) ws2
- // firstline_b goes from nws2 to (but not including) ws3
- // firstline_c goes from nws3 to (but not including) ws4
- //
- // In the code:
- // ws1 == whitespace_1_idx_
- // nws1 == non_whitespace_1_idx_
- // ws2 == whitespace_2_idx_
- // nws2 == non_whitespace_2_idx_
- // ws3 == whitespace_3_idx_
- // nws3 == non_whitespace_3_idx_
- // ws4 == whitespace_4_idx_
- BalsaBuffer::Blocks::size_type firstline_buffer_base_idx_;
- size_t whitespace_1_idx_;
- size_t non_whitespace_1_idx_;
- size_t whitespace_2_idx_;
- size_t non_whitespace_2_idx_;
- size_t whitespace_3_idx_;
- size_t non_whitespace_3_idx_;
- size_t whitespace_4_idx_;
- size_t end_of_firstline_idx_;
-
- bool transfer_encoding_is_chunked_;
-
- HeaderLines header_lines_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_H_
diff --git a/net/tools/flip_server/balsa_headers_test.cc b/net/tools/flip_server/balsa_headers_test.cc
deleted file mode 100644
index 241fee1..0000000
--- a/net/tools/flip_server/balsa_headers_test.cc
+++ /dev/null
@@ -1,392 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/balsa_headers.h"
-
-#include <iterator>
-#include <string>
-#include <vector>
-
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/string_piece.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace net {
-
-using ::base::StringPiece;
-
-class BalsaBufferTest : public ::testing::Test {
- public:
- virtual void SetUp() OVERRIDE {
- buffer_.reset(new BalsaBuffer);
- anotherBuffer_.reset(new BalsaBuffer);
- }
-
- protected:
- scoped_ptr<BalsaBuffer> buffer_;
- scoped_ptr<BalsaBuffer> anotherBuffer_;
-};
-
-namespace {
-
-class BalsaHeadersTest: public ::testing::Test {
- public:
- virtual void SetUp() OVERRIDE {
- headers_.reset(new BalsaHeaders);
- }
-
- protected:
- scoped_ptr<BalsaHeaders> headers_;
-};
-
-class StringBuffer {
- public:
- void Write(const char* p, size_t size) {
- string_ += std::string(p, size);
- }
- const std::string& string() {return string_;}
-
- private:
- std::string string_;
-};
-
-TEST_F(BalsaBufferTest, EmptyBuffer) {
- ASSERT_EQ(1u, buffer_->num_blocks());
-}
-
-TEST_F(BalsaBufferTest, Write) {
- size_t index1, index2;
- StringPiece sp1 = buffer_->Write(StringPiece("hello"), &index1);
- StringPiece sp2 = buffer_->Write(StringPiece(", world"), &index2);
-
- ASSERT_EQ(2u, buffer_->num_blocks());
- ASSERT_EQ("hello", sp1);
- ASSERT_EQ(", world", sp2);
- ASSERT_EQ(1u, index1);
- ASSERT_EQ(1u, index2);
- ASSERT_EQ("hello, world",
- StringPiece(buffer_->GetPtr(1), buffer_->bytes_used(1)));
-}
-
-TEST_F(BalsaBufferTest, WriteLongData) {
- size_t index1, index2, index3;
- std::string as(2, 'a');
- std::string bs(BalsaBuffer::kDefaultBlocksize + 1, 'b');
- std::string cs(4, 'c');
-
- StringPiece sp1 = buffer_->Write(as, &index1);
- StringPiece sp2 = buffer_->Write(bs, &index2);
- StringPiece sp3 = buffer_->Write(cs, &index3);
-
- ASSERT_EQ(3u, buffer_->num_blocks());
- ASSERT_EQ(as, sp1);
- ASSERT_EQ(bs, sp2);
- ASSERT_EQ(cs, sp3);
- ASSERT_EQ(1u, index1);
- ASSERT_EQ(2u, index2);
- ASSERT_EQ(1u, index3);
- ASSERT_EQ("aacccc", StringPiece(buffer_->GetPtr(1), buffer_->bytes_used(1)));
- ASSERT_EQ(sp2, StringPiece(buffer_->GetPtr(2), buffer_->bytes_used(2)));
-}
-
-TEST_F(BalsaBufferTest, WriteToContiguousBuffer) {
- std::string as(2, 'a');
- std::string bs(BalsaBuffer::kDefaultBlocksize + 1, 'b');
- std::string cs(4, 'c');
-
- buffer_->WriteToContiguousBuffer(as);
- buffer_->WriteToContiguousBuffer(bs);
- buffer_->WriteToContiguousBuffer(cs);
-
- ASSERT_EQ(1u, buffer_->num_blocks());
- ASSERT_EQ(as + bs + cs,
- StringPiece(buffer_->GetPtr(0), buffer_->bytes_used(0)));
-}
-
-TEST_F(BalsaBufferTest, NoMoreWriteToContiguousBuffer) {
- size_t index1, index2;
- StringPiece sp1 = buffer_->Write(StringPiece("hello"), &index1);
- buffer_->NoMoreWriteToContiguousBuffer();
- StringPiece sp2 = buffer_->Write(StringPiece(", world"), &index2);
-
- ASSERT_EQ(2u, buffer_->num_blocks());
- ASSERT_EQ("hello", sp1);
- ASSERT_EQ(", world", sp2);
- ASSERT_EQ(1u, index1);
- ASSERT_EQ(0u, index2);
- ASSERT_EQ(sp1, StringPiece(buffer_->GetPtr(1), buffer_->bytes_used(1)));
- ASSERT_EQ(sp2, StringPiece(buffer_->GetPtr(0), buffer_->bytes_used(0)));
-}
-
-TEST_F(BalsaBufferTest, Clear) {
- buffer_->Write("hello", NULL);
- ASSERT_EQ(2u, buffer_->num_blocks());
- buffer_->Clear();
- ASSERT_EQ(1u, buffer_->num_blocks());
-}
-
-TEST_F(BalsaBufferTest, Swap) {
- buffer_->Write("hello", NULL);
-
- ASSERT_EQ(2u, buffer_->num_blocks());
- ASSERT_EQ(1u, anotherBuffer_->num_blocks());
-
- buffer_->Swap(anotherBuffer_.get());
-
- ASSERT_EQ(1u, buffer_->num_blocks());
- ASSERT_EQ(2u, anotherBuffer_->num_blocks());
- ASSERT_EQ("hello",
- StringPiece(anotherBuffer_->GetPtr(1),
- anotherBuffer_->bytes_used(1)));
-}
-
-TEST_F(BalsaBufferTest, CopyFrom) {
- buffer_->Write("hello", NULL);
-
- ASSERT_EQ(2u, buffer_->num_blocks());
- ASSERT_EQ(1u, anotherBuffer_->num_blocks());
-
- anotherBuffer_->CopyFrom(*buffer_);
-
- ASSERT_EQ(2u, buffer_->num_blocks());
- ASSERT_EQ(2u, anotherBuffer_->num_blocks());
- ASSERT_EQ("hello", StringPiece(buffer_->GetPtr(1), buffer_->bytes_used(1)));
- ASSERT_EQ("hello",
- StringPiece(anotherBuffer_->GetPtr(1),
- anotherBuffer_->bytes_used(1)));
-}
-
-TEST_F(BalsaHeadersTest, AppendHeader) {
- headers_->AppendHeader("key1", "value1");
- headers_->AppendHeader("key2", "value2");
- headers_->AppendHeader("key3", "value3");
- headers_->AppendHeader("key3", "value3.1");
- headers_->AppendHeader("key3", "value3.2");
-
- ASSERT_EQ(5, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
- ASSERT_EQ("value1", headers_->GetHeader("key1"));
- ASSERT_EQ("value2", headers_->GetHeader("key2"));
- ASSERT_EQ("value3", headers_->GetHeader("key3"));
-
- std::vector<base::StringPiece> v1, v2, v3;
- std::string s1, s2, s3;
- headers_->GetAllOfHeader("key1", &v1);
- headers_->GetAllOfHeader("key2", &v2);
- headers_->GetAllOfHeader("key3", &v3);
- headers_->GetAllOfHeaderAsString("key1", &s1);
- headers_->GetAllOfHeaderAsString("key2", &s2);
- headers_->GetAllOfHeaderAsString("key3", &s3);
-
- ASSERT_EQ(1u, v1.size());
- ASSERT_EQ(1u, v2.size());
- ASSERT_EQ(3u, v3.size());
- ASSERT_EQ("value1", v1[0]);
- ASSERT_EQ("value2", v2[0]);
- ASSERT_EQ("value3", v3[0]);
- ASSERT_EQ("value3.1", v3[1]);
- ASSERT_EQ("value3.2", v3[2]);
- ASSERT_EQ("value1", s1);
- ASSERT_EQ("value2", s2);
- ASSERT_EQ("value3,value3.1,value3.2", s3);
-}
-
-TEST_F(BalsaHeadersTest, ReplaceOrAppendHeader) {
- headers_->ReplaceOrAppendHeader("key1", "value1");
- headers_->ReplaceOrAppendHeader("key1", "value2");
-
- ASSERT_EQ(1, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
- ASSERT_EQ("value2", headers_->GetHeader("key1"));
-
- std::vector<base::StringPiece> v;
- headers_->GetAllOfHeader("key1", &v);
-
- ASSERT_EQ(1u, v.size());
- ASSERT_EQ("value2", v[0]);
-}
-
-TEST_F(BalsaHeadersTest, AppendToHeader) {
- headers_->AppendToHeader("key1", "value1");
- headers_->AppendToHeader("keY1", "value2");
-
- ASSERT_EQ(1, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
- ASSERT_EQ("value1,value2", headers_->GetHeader("key1"));
-
- std::vector<base::StringPiece> v;
- std::string s;
- headers_->GetAllOfHeader("key1", &v);
- headers_->GetAllOfHeaderAsString("keY1", &s);
-
- ASSERT_EQ(1u, v.size());
- ASSERT_EQ("value1,value2", v[0]);
- ASSERT_EQ("value1,value2", s);
-}
-
-TEST_F(BalsaHeadersTest, PrepentToHeader) {
- headers_->PrependToHeader("key1", "value1");
- headers_->PrependToHeader("key1", "value2");
-
- ASSERT_EQ(1, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
- ASSERT_EQ("value2,value1", headers_->GetHeader("key1"));
-
- std::vector<base::StringPiece> v;
- std::string s;
- headers_->GetAllOfHeader("key1", &v);
- headers_->GetAllOfHeaderAsString("key1", &s);
-
- ASSERT_EQ(1u, v.size());
- ASSERT_EQ("value2,value1", v[0]);
- ASSERT_EQ("value2,value1", s);
-}
-
-TEST_F(BalsaHeadersTest, HasHeader) {
- headers_->AppendHeader("key1", "value1");
-
- ASSERT_TRUE(headers_->HasHeader("key1"));
- ASSERT_FALSE(headers_->HasHeader("value1"));
- ASSERT_FALSE(headers_->HasHeader("key2"));
-}
-
-TEST_F(BalsaHeadersTest, HasNonEmptyHeader) {
- headers_->AppendHeader("key1", "value1");
- headers_->AppendHeader("key2", "");
-
- ASSERT_TRUE(headers_->HasNonEmptyHeader("key1"));
- ASSERT_FALSE(headers_->HasNonEmptyHeader("key2"));
- ASSERT_FALSE(headers_->HasNonEmptyHeader("key3"));
-}
-
-TEST_F(BalsaHeadersTest, GetHeaderPosition) {
- headers_->AppendHeader("key1", "value1");
- headers_->AppendHeader("key2", "value2");
- headers_->AppendHeader("key3", "value3");
-
- BalsaHeaders::const_header_lines_iterator i =
- headers_->GetHeaderPosition("key2");
-
- ASSERT_EQ(headers_->header_lines_end(),
- headers_->GetHeaderPosition("foobar"));
- ASSERT_EQ(headers_->header_lines_begin(),
- headers_->GetHeaderPosition("key1"));
- ASSERT_NE(headers_->header_lines_end(), i);
- ASSERT_EQ("key2", i->first);
- ASSERT_EQ("value2", i->second);
- ++i;
- ASSERT_EQ("key3", i->first);
- ASSERT_EQ("value3", i->second);
- ++i;
- ASSERT_EQ(headers_->header_lines_end(), i);
-}
-
-TEST_F(BalsaHeadersTest, GetIteratorForKey) {
- headers_->AppendHeader("key1", "value1");
- headers_->AppendHeader("key2", "value2");
- headers_->AppendHeader("key1", "value1.1");
- headers_->AppendHeader("key3", "value3");
- headers_->AppendHeader("KEY1", "value1.2");
-
- BalsaHeaders::const_header_lines_key_iterator i =
- headers_->GetIteratorForKey("key1");
-
- ASSERT_EQ(headers_->header_lines_key_end(),
- headers_->GetIteratorForKey("foobar"));
- ASSERT_NE(headers_->header_lines_key_end(), i);
- ASSERT_EQ("key1", i->first);
- ASSERT_EQ("value1", i->second);
- ++i;
- ASSERT_EQ("key1", i->first);
- ASSERT_EQ("value1.1", i->second);
- ++i;
- ASSERT_EQ("KEY1", i->first);
- ASSERT_EQ("value1.2", i->second);
- ++i;
- ASSERT_EQ(headers_->header_lines_key_end(), i);
-}
-
-TEST_F(BalsaHeadersTest, RemoveAllOfHeader) {
- headers_->AppendHeader("key1", "value1");
- headers_->AppendHeader("key2", "value2");
- headers_->AppendHeader("key1", "value1.1");
- headers_->AppendHeader("key3", "value3");
- headers_->AppendHeader("key1", "value1.2");
- headers_->AppendHeader("kEY1", "value1.3");
-
- ASSERT_EQ(6, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
- headers_->RemoveAllOfHeader("key1");
- ASSERT_EQ(2, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
-}
-
-TEST_F(BalsaHeadersTest, RemoveAllHeadersWithPrefix) {
- headers_->AppendHeader("1key", "value1");
- headers_->AppendHeader("2key", "value2");
- headers_->AppendHeader("1kEz", "value1.1");
- headers_->AppendHeader("key3", "value3");
- headers_->AppendHeader("1KEEjkladf", "value1.2");
-
- ASSERT_EQ(5, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
- headers_->RemoveAllHeadersWithPrefix("1ke");
- ASSERT_EQ(2, std::distance(headers_->header_lines_begin(),
- headers_->header_lines_end()));
-}
-
-TEST_F(BalsaHeadersTest, WriteRequestHeaderAndEndingToBuffer) {
- headers_->AppendHeader("key1", "value1");
- headers_->AppendHeader("key2", "value2");
- headers_->AppendHeader("key1", "value1.1");
-
- headers_->SetRequestFirstlineFromStringPieces("GET", "/", "HTTP/1.0");
-
- std::string expected = "GET / HTTP/1.0\r\n"
- "key1: value1\r\n"
- "key2: value2\r\n"
- "key1: value1.1\r\n\r\n";
- StringBuffer buffer;
- headers_->WriteHeaderAndEndingToBuffer(&buffer);
- ASSERT_EQ(expected, buffer.string());
-}
-
-TEST_F(BalsaHeadersTest, WriteResponseHeaderAndEndingToBuffer) {
- headers_->AppendHeader("key1", "value1");
- headers_->AppendHeader("key2", "value2");
- headers_->AppendHeader("key1", "value1.1");
-
- headers_->SetResponseFirstlineFromStringPieces("HTTP/1.0", "200", "OK");
-
- std::string expected = "HTTP/1.0 200 OK\r\n"
- "key1: value1\r\n"
- "key2: value2\r\n"
- "key1: value1.1\r\n\r\n";
- StringBuffer buffer;
- headers_->WriteHeaderAndEndingToBuffer(&buffer);
- ASSERT_EQ(expected, buffer.string());
-}
-
-TEST_F(BalsaHeadersTest, RequestFirstLine) {
- headers_->SetRequestFirstlineFromStringPieces("HEAD", "/path", "HTTP/1.1");
-
- ASSERT_EQ("HEAD /path HTTP/1.1", headers_->first_line());
- ASSERT_EQ("HEAD", headers_->request_method());
- ASSERT_EQ("/path", headers_->request_uri());
- ASSERT_EQ("HTTP/1.1", headers_->request_version());
-}
-
-TEST_F(BalsaHeadersTest, ResponseFirstLine) {
- headers_->SetRequestFirstlineFromStringPieces("HTTP/1.0", "403", "FORBIDDEN");
-
- ASSERT_EQ("HTTP/1.0 403 FORBIDDEN", headers_->first_line());
- ASSERT_EQ("HTTP/1.0", headers_->response_version());
- ASSERT_EQ("403", headers_->response_code());
- ASSERT_EQ("FORBIDDEN", headers_->response_reason_phrase());
-}
-
-} // namespace
-
-} // namespace net
diff --git a/net/tools/flip_server/balsa_headers_token_utils.cc b/net/tools/flip_server/balsa_headers_token_utils.cc
deleted file mode 100644
index b47debf..0000000
--- a/net/tools/flip_server/balsa_headers_token_utils.cc
+++ /dev/null
@@ -1,142 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/balsa_headers_token_utils.h"
-#include "net/tools/flip_server/string_piece_utils.h"
-
-namespace net {
-
-inline void BalsaHeadersTokenUtils::TokenizeHeaderLine(
- const BalsaHeaders& headers,
- const BalsaHeaders::HeaderLineDescription& header_line,
- BalsaHeaders::HeaderTokenList* tokens) {
- CHECK(tokens);
-
- // Find where this line is stored
- const char* stream_begin = headers.GetPtr(header_line.buffer_base_idx);
-
- // Determine the boundaries of the value
- const char* value_begin = stream_begin + header_line.value_begin_idx;
- const char* line_end = stream_begin + header_line.last_char_idx;
-
- // Tokenize
- ParseTokenList(value_begin, line_end, tokens);
-}
-
-void BalsaHeadersTokenUtils::RemoveLastTokenFromHeaderValue(
- const base::StringPiece& key, BalsaHeaders* headers) {
- BalsaHeaders::HeaderLines::iterator it =
- headers->GetHeaderLinesIterator(key, headers->header_lines_.begin());
- if (it == headers->header_lines_.end()) {
- DLOG(WARNING) << "Attempting to remove last token from a non-existent "
- << "header \"" << key << "\"";
- return;
- }
-
- // Find the last line with that key.
- BalsaHeaders::HeaderLines::iterator header_line;
- do {
- header_line = it;
- it = headers->GetHeaderLinesIterator(key, it + 1);
- }
- while (it != headers->header_lines_.end());
-
- // Tokenize just that line.
- BalsaHeaders::HeaderTokenList tokens;
- TokenizeHeaderLine(*headers, *header_line, &tokens);
-
- if (tokens.empty()) {
- DLOG(WARNING) << "Attempting to remove a token from an empty header value "
- << "for header \"" << key << "\"";
- header_line->skip = true; // remove the whole line
- } else if (tokens.size() == 1) {
- header_line->skip = true; // remove the whole line
- } else {
- // Shrink the line size and leave the extra data in the buffer.
- const base::StringPiece& new_last_token = tokens[tokens.size() - 2];
- const char* last_char_address =
- new_last_token.data() + new_last_token.size() - 1;
- const char* stream_begin = headers->GetPtr(header_line->buffer_base_idx);
-
- header_line->last_char_idx = last_char_address - stream_begin + 1;
- }
-}
-
-bool BalsaHeadersTokenUtils::CheckHeaderForLastToken(
- const BalsaHeaders& headers,
- const base::StringPiece& key,
- const base::StringPiece& token) {
- BalsaHeaders::const_header_lines_key_iterator it =
- headers.GetIteratorForKey(key);
- if (it == headers.header_lines_key_end())
- return false;
-
- // Find the last line
- BalsaHeaders::const_header_lines_key_iterator header_line = it;
- do {
- header_line = it;
- ++it;
- }
- while (it != headers.header_lines_key_end());
-
- // Tokenize just that line
- BalsaHeaders::HeaderTokenList tokens;
- ParseTokenList(header_line->second.begin(), header_line->second.end(),
- &tokens);
-
- return !tokens.empty() &&
- StringPieceUtils::StartsWithIgnoreCase(tokens.back(), token);
-}
-
-void BalsaHeadersTokenUtils::TokenizeHeaderValue(
- const BalsaHeaders& headers,
- const base::StringPiece& key,
- BalsaHeaders::HeaderTokenList* tokens) {
- CHECK(tokens);
- tokens->clear();
-
- // We may have more then 1 line with the same header key. Tokenize them all
- // and stick all the tokens into the same list.
- for (BalsaHeaders::const_header_lines_key_iterator header_line =
- headers.GetIteratorForKey(key);
- header_line != headers.header_lines_key_end(); ++header_line) {
- ParseTokenList(header_line->second.begin(), header_line->second.end(),
- tokens);
- }
-}
-
-void BalsaHeadersTokenUtils::ParseTokenList(
- const char* start,
- const char* end,
- BalsaHeaders::HeaderTokenList* tokens) {
- if (start == end) {
- return;
- }
- while (true) {
- // search for first nonwhitespace, non separator char.
- while (*start == ',' || *start <= ' ') {
- ++start;
- if (start == end) {
- return;
- }
- }
- // found. marked.
- const char* nws = start;
-
- // search for next whitspace or separator char.
- while (*start != ',' && *start > ' ') {
- ++start;
- if (start == end) {
- if (nws != start) {
- tokens->push_back(base::StringPiece(nws, start - nws));
- }
- return;
- }
- }
- tokens->push_back(base::StringPiece(nws, start - nws));
- }
-}
-
-} // namespace net
-
diff --git a/net/tools/flip_server/balsa_headers_token_utils.h b/net/tools/flip_server/balsa_headers_token_utils.h
deleted file mode 100644
index f50c606..0000000
--- a/net/tools/flip_server/balsa_headers_token_utils.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-// Utility class that performs basic operations on header value tokens: parsing
-// them out, checking for presense of certain tokens, and removing them.
-
-#ifndef NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_TOKEN_UTILS_H_
-#define NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_TOKEN_UTILS_H_
-
-#include "base/strings/string_piece.h"
-#include "net/tools/flip_server/balsa_headers.h"
-
-namespace net {
-
-class BalsaHeadersTokenUtils {
- public:
- // All the functions below respect multiple header lines with the same key.
-
- // Checks whether the last header token matches a given value. Useful to
- // check the outer-most content or transfer-encoding, for example. In the
- // presence of multiple header lines with given key, the last token of the
- // last line is compared.
- static bool CheckHeaderForLastToken(const BalsaHeaders& headers,
- const base::StringPiece& key,
- const base::StringPiece& token);
-
- // Tokenizes header value for a given key. In the presence of multiple lines
- // with that key, all of them will be tokenized and tokens will be added to
- // the list in the order in which they are encountered.
- static void TokenizeHeaderValue(const BalsaHeaders& headers,
- const base::StringPiece& key,
- BalsaHeaders::HeaderTokenList* tokens);
-
- // Removes the last token from the header value. In the presence of multiple
- // header lines with given key, will remove the last token of the last line.
- // Can be useful if the last encoding has to be removed.
- static void RemoveLastTokenFromHeaderValue(const base::StringPiece& key,
- BalsaHeaders* headers);
-
- // Given a pointer to the beginning and the end of the header value
- // in some buffer, populates tokens list with beginning and end indices
- // of all tokens present in the value string.
- static void ParseTokenList(const char* start,
- const char* end,
- BalsaHeaders::HeaderTokenList* tokens);
-
- private:
- // Helper function to tokenize a header line once we have its description.
- static void TokenizeHeaderLine(
- const BalsaHeaders& headers,
- const BalsaHeaders::HeaderLineDescription& line,
- BalsaHeaders::HeaderTokenList* tokens);
-
- BalsaHeadersTokenUtils(); // Prohibit instantiation
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_BALSA_HEADERS_TOKEN_UTILS_H_
-
diff --git a/net/tools/flip_server/balsa_visitor_interface.h b/net/tools/flip_server/balsa_visitor_interface.h
deleted file mode 100644
index 2542723..0000000
--- a/net/tools/flip_server/balsa_visitor_interface.h
+++ /dev/null
@@ -1,180 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_BALSA_VISITOR_INTERFACE_H_
-#define NET_TOOLS_FLIP_SERVER_BALSA_VISITOR_INTERFACE_H_
-
-#include <cstddef>
-
-namespace net {
-
-class BalsaFrame;
-class BalsaHeaders;
-
-// By default the BalsaFrame instantiates a class derived from this interface
-// which does absolutely nothing. If you'd prefer to have interesting
-// functionality execute when any of the below functions are called by the
-// BalsaFrame, then you should subclass it, and set an instantiation of your
-// subclass as the current visitor for the BalsaFrame class using
-// BalsaFrame::set_visitor().
-class BalsaVisitorInterface {
- public:
- virtual ~BalsaVisitorInterface() {}
-
- // Summary:
- // This is how the BalsaFrame passes you the raw input which it knows to
- // be a part of the body. To be clear, every byte of the Balsa which isn't
- // part of the header (or its framing), or trailers will be passed through
- // this function. This includes data as well as chunking framing.
- // Arguments:
- // input - contains the bytes available for read.
- // size - contains the number of bytes it is safe to read from input.
- virtual void ProcessBodyInput(const char *input, size_t size) = 0;
-
- // Summary:
- // This is like ProcessBodyInput, but it will only include those parts of
- // the body which would be stored by a program such as wget, i.e. the bytes
- // indicating chunking (it will have been omitted). Trailers will not be
- // passed in through this function-- they'll be passed in through
- // ProcessTrailers.
- // Arguments:
- // input - contains the bytes available for read.
- // size - contains the number of bytes it is safe to read from input.
- virtual void ProcessBodyData(const char *input, size_t size) = 0;
-
- // Summary:
- // BalsaFrame passes the raw header data through this function. This is
- // not cleaned up in any way.
- // Arguments:
- // input - contains the bytes available for read.
- // size - contains the number of bytes it is safe to read from input.
- virtual void ProcessHeaderInput(const char *input, size_t size) = 0;
-
- // Summary:
- // BalsaFrame passes the raw trailer data through this function. This is
- // not cleaned up in any way. Note that trailers only occur in a message
- // if there was a chunked encoding, and not always then.
- //
- // Arguments:
- // input - contains the bytes available for read.
- // size - contains the number of bytes it is safe to read from input.
- virtual void ProcessTrailerInput(const char *input, size_t size) = 0;
-
- // Summary:
- // Since the BalsaFrame already has to parse the headers in order to
- // determine proper framing, it might as well pass the parsed and
- // cleaned-up results to whatever might need it. This function exists for
- // that purpose-- parsed headers are passed into this function.
- // Arguments:
- // headers - contains the parsed headers in the order in which
- // they occured in the header.
- virtual void ProcessHeaders(const BalsaHeaders& headers) = 0;
-
- // Summary:
- // Called when the first line of the message is parsed, in this case, for a
- // request.
- // Arguments:
- // line_input - pointer to the beginning of the first line string.
- // line_length - length of the first line string. (i.e. the numer of
- // bytes it is safe to read from line_ptr)
- // method_input - pointer to the beginning of the method string
- // method_length - length of the method string (i.e. the number
- // of bytes it is safe to read from method_input)
- // request_uri_input - pointer to the beginning of the request uri
- // string.
- // request_uri_length - length of the method string (i.e. the number
- // of bytes it is safe to read from method_input)
- // version_input - pointer to the beginning of the version string.
- // version_length - length of the version string (i.e. the number
- // of bytes it i ssafe to read from version_input)
- virtual void ProcessRequestFirstLine(const char* line_input,
- size_t line_length,
- const char* method_input,
- size_t method_length,
- const char* request_uri_input,
- size_t request_uri_length,
- const char* version_input,
- size_t version_length) = 0;
-
- // Summary:
- // Called when the first line of the message is parsed, in this case, for a
- // response.
- // Arguments:
- // line_input - pointer to the beginning of the first line string.
- // line_length - length of the first line string. (i.e. the numer of
- // bytes it is safe to read from line_ptr)
- // version_input - pointer to the beginning of the version string.
- // version_length - length of the version string (i.e. the number
- // of bytes it i ssafe to read from version_input)
- // status_input - pointer to the beginning of the status string
- // status_length - length of the status string (i.e. the number
- // of bytes it is safe to read from status_input)
- // reason_input - pointer to the beginning of the reason string
- // reason_length - length of the reason string (i.e. the number
- // of bytes it is safe to read from reason_input)
- virtual void ProcessResponseFirstLine(const char *line_input,
- size_t line_length,
- const char *version_input,
- size_t version_length,
- const char *status_input,
- size_t status_length,
- const char *reason_input,
- size_t reason_length) = 0;
-
- // Called when a chunk length is parsed.
- // Arguments:
- // chunk length - the length of the next incoming chunk.
- virtual void ProcessChunkLength(size_t chunk_length) = 0;
-
- // Summary:
- // BalsaFrame passes the raw chunk extension data through this function.
- // The data is not cleaned up at all, use
- // BalsaFrame::ProcessChunkExtentions to get the parsed and cleaned up
- // chunk extensions.
- //
- // Arguments:
- // input - contains the bytes available for read.
- // size - contains the number of bytes it is safe to read from input.
- virtual void ProcessChunkExtensions(const char* input, size_t size) = 0;
-
- // Summary:
- // Called when the header is framed and processed.
- virtual void HeaderDone() = 0;
-
- // Summary:
- // Called when the message is framed and processed.
- virtual void MessageDone() = 0;
-
- // Summary:
- // Called when an error is detected while parsing the header.
- // Arguments:
- // framer - the framer in which an error occured.
- virtual void HandleHeaderError(BalsaFrame* framer) = 0;
-
- // Summary:
- // Called when something meriting a warning is detected while
- // parsing the header.
- // Arguments:
- // framer - the framer in which an error occured.
- virtual void HandleHeaderWarning(BalsaFrame* framer) = 0;
-
- // Summary:
- // Called when an error is detected while parsing a chunk.
- // Arguments:
- // framer - the framer in which an error occured.
- virtual void HandleChunkingError(BalsaFrame* framer) = 0;
-
- // Summary:
- // Called when an error is detected while handling the entity-body.
- // Currently, this can only be called when there is an error
- // with the BytesSpliced() function, but in the future other interesting
- // errors could occur.
- // Arguments:
- // framer - the framer in which an error occured.
- virtual void HandleBodyError(BalsaFrame* framer) = 0;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_BALSA_VISITOR_INTERFACE_H_
diff --git a/net/tools/flip_server/buffer_interface.h b/net/tools/flip_server/buffer_interface.h
deleted file mode 100644
index ec061c9..0000000
--- a/net/tools/flip_server/buffer_interface.h
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_BUFFER_INTERFACE_H__
-#define NET_TOOLS_FLIP_SERVER_BUFFER_INTERFACE_H__
-
-namespace net {
-
-class BufferInterface {
- public:
-
- // Returns the bytes which can be read from the buffer. There is no
- // guarantee that the bytes are contiguous.
- virtual int ReadableBytes() const = 0;
-
- // Summary:
- // returns the size of this buffer
- // Returns:
- // size of this buffer.
- virtual int BufferSize() const = 0;
-
- // Summary:
- // returns the number of bytes free in this buffer.
- // Returns:
- // number of bytes free.
- virtual int BytesFree() const = 0;
-
- // Summary:
- // Returns true if empty.
- // Returns:
- // true - if empty
- // false - otherwise
- virtual bool Empty() const = 0;
-
- // Summary:
- // Returns true if the buffer is full.
- virtual bool Full() const = 0;
-
- // Summary:
- // returns the number of characters written.
- // appends up-to-'size' bytes to the buffer.
- // Args:
- // bytes - bytes which are read, and copied into the buffer.
- // size - number of bytes which are read and copied.
- // this number shall be >= 0.
- virtual int Write(const char* bytes, int size) = 0;
-
- // Summary:
- // Gets a pointer which can be written to (assigned to).
- // this pointer (and size) can be used in functions like
- // recv() or read(), etc.
- // If *size is zero upon returning from this function, that it
- // is unsafe to dereference *ptr.
- // Args:
- // ptr - assigned a pointer to which we can write
- // size - the amount of data (in bytes) that it is safe to write to ptr.
- virtual void GetWritablePtr(char **ptr, int* size) const = 0;
-
- // Summary:
- // Gets a pointer which can be read from
- // this pointer (and size) can be used in functions like
- // send() or write(), etc.
- // If *size is zero upon returning from this function, that it
- // is unsafe to dereference *ptr.
- // Args:
- // ptr - assigned a pointer from which we may read
- // size - the amount of data (in bytes) that it is safe to read
- virtual void GetReadablePtr(char **ptr, int* size) const = 0;
-
- // Summary:
- // Reads bytes out of the buffer, and writes them into 'bytes'.
- // Returns the number of bytes read.
- // Consumes bytes from the buffer (possibly, but not necessarily
- // rendering them free)
- // Args:
- // bytes - the pointer into which bytes are read from this buffer
- // and written into
- // size - number of bytes which are read and copied.
- // this number shall be >= 0.
- // Returns:
- // the number of bytes read from 'bytes'
- virtual int Read(char* bytes, int size) = 0;
-
- // Summary:
- // removes all data from the buffer
- virtual void Clear() = 0;
-
- // Summary:
- // reserves contiguous writable empty space in the buffer of size bytes.
- // Returns true if the reservation is successful.
- // If a derive class chooses not to implement reservation, its
- // implementation should return false.
- virtual bool Reserve(int size) = 0;
-
- // Summary:
- // removes the oldest 'amount_to_consume' characters from this buffer,
- // Args:
- // amount_to_advance - .. this should be self-explanatory =)
- // this number shall be >= 0.
- virtual void AdvanceReadablePtr(int amount_to_advance) = 0;
-
- // Summary:
- // Moves the internal pointers around such that the
- // amount of data specified here is expected to
- // already be resident (as if it was Written)
- // Args:
- // amount_to_advance - self explanatory.
- // this number shall be >= 0.
- virtual void AdvanceWritablePtr(int amount_to_advance) = 0;
-
- virtual ~BufferInterface() {}
-
- protected:
- BufferInterface() {}
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_BUFFER_INTERFACE__H__
-
diff --git a/net/tools/flip_server/epoll_server.cc b/net/tools/flip_server/epoll_server.cc
deleted file mode 100644
index 0e09a6d..0000000
--- a/net/tools/flip_server/epoll_server.cc
+++ /dev/null
@@ -1,820 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/epoll_server.h"
-
-#include <unistd.h> // For read, pipe, close and write.
-#include <stdlib.h> // for abort
-#include <errno.h> // for errno and strerror_r
-#include <algorithm>
-#include <utility>
-#include <vector>
-
-#include "base/logging.h"
-#include "base/timer/timer.h"
-
-// Design notes: An efficient implementation of ready list has the following
-// desirable properties:
-//
-// A. O(1) insertion into/removal from the list in any location.
-// B. Once the callback is found by hash lookup using the fd, the lookup of
-// corresponding entry in the list is O(1).
-// C. Safe insertion into/removal from the list during list iteration. (The
-// ready list's purpose is to enable completely event driven I/O model.
-// Thus, all the interesting bits happen in the callback. It is critical
-// to not place any restriction on the API during list iteration.
-//
-// The current implementation achieves these goals with the following design:
-//
-// - The ready list is constructed as a doubly linked list to enable O(1)
-// insertion/removal (see man 3 queue).
-// - The forward and backward links are directly embedded inside the
-// CBAndEventMask struct. This enables O(1) lookup in the list for a given
-// callback. (Techincally, we could've used std::list of hash_set::iterator,
-// and keep a list::iterator in CBAndEventMask to achieve the same effect.
-// However, iterators have two problems: no way to portably invalidate them,
-// and no way to tell whether an iterator is singular or not. The only way to
-// overcome these issues is to keep bools in both places, but that throws off
-// memory alignment (up to 7 wasted bytes for each bool). The extra level of
-// indirection will also likely be less cache friendly. Direct manipulation
-// of link pointers makes it easier to retrieve the CBAndEventMask from the
-// list, easier to check whether an CBAndEventMask is in the list, uses less
-// memory (save 32 bytes/fd), and does not affect cache usage (we need to
-// read in the struct to use the callback anyway).)
-// - Embed the fd directly into CBAndEventMask and switch to using hash_set.
-// This removes the need to store hash_map::iterator in the list just so that
-// we can get both the fd and the callback.
-// - The ready list is "one shot": each entry is removed before OnEvent is
-// called. This removes the mutation-while-iterating problem.
-// - Use two lists to keep track of callbacks. The ready_list_ is the one used
-// for registration. Before iteration, the ready_list_ is swapped into the
-// tmp_list_. Once iteration is done, tmp_list_ will be empty, and
-// ready_list_ will have all the new ready fds.
-
-// The size we use for buffers passed to strerror_r
-static const int kErrorBufferSize = 256;
-
-namespace net {
-
-// Clears the pipe and returns. Used for waking the epoll server up.
-class ReadPipeCallback : public EpollCallbackInterface {
- public:
- virtual void OnEvent(int fd, EpollEvent* event) OVERRIDE {
- DCHECK(event->in_events == EPOLLIN);
- int data;
- int data_read = 1;
- // Read until the pipe is empty.
- while (data_read > 0) {
- data_read = read(fd, &data, sizeof(data));
- }
- }
- virtual void OnShutdown(EpollServer *eps, int fd) OVERRIDE {}
- virtual void OnRegistration(EpollServer*, int, int) OVERRIDE {}
- virtual void OnModification(int, int) OVERRIDE {} // COV_NF_LINE
- virtual void OnUnregistration(int, bool) OVERRIDE {} // COV_NF_LINE
-};
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-EpollServer::EpollServer()
- : epoll_fd_(epoll_create(1024)),
- timeout_in_us_(0),
- recorded_now_in_us_(0),
- ready_list_size_(0),
- wake_cb_(new ReadPipeCallback),
- read_fd_(-1),
- write_fd_(-1),
- in_wait_for_events_and_execute_callbacks_(false),
- in_shutdown_(false) {
- // ensure that the epoll_fd_ is valid.
- CHECK_NE(epoll_fd_, -1);
- LIST_INIT(&ready_list_);
- LIST_INIT(&tmp_list_);
-
- int pipe_fds[2];
- if (pipe(pipe_fds) < 0) {
- // Unfortunately, it is impossible to test any such initialization in
- // a constructor (as virtual methods do not yet work).
- // This -could- be solved by moving initialization to an outside
- // call...
- int saved_errno = errno;
- char buf[kErrorBufferSize];
- LOG(FATAL) << "Error " << saved_errno
- << " in pipe(): " << strerror_r(saved_errno, buf, sizeof(buf));
- }
- read_fd_ = pipe_fds[0];
- write_fd_ = pipe_fds[1];
- RegisterFD(read_fd_, wake_cb_.get(), EPOLLIN);
-}
-
-void EpollServer::CleanupFDToCBMap() {
- FDToCBMap::iterator cb_iter = cb_map_.begin();
- while (cb_iter != cb_map_.end()) {
- int fd = cb_iter->fd;
- CB* cb = cb_iter->cb;
-
- cb_iter->in_use = true;
- if (cb) {
- cb->OnShutdown(this, fd);
- }
-
- cb_map_.erase(cb_iter);
- cb_iter = cb_map_.begin();
- }
-}
-
-void EpollServer::CleanupTimeToAlarmCBMap() {
- TimeToAlarmCBMap::iterator erase_it;
-
- // Call OnShutdown() on alarms. Note that the structure of the loop
- // is similar to the structure of loop in the function HandleAlarms()
- for (TimeToAlarmCBMap::iterator i = alarm_map_.begin();
- i != alarm_map_.end();
- ) {
- // Note that OnShutdown() can call UnregisterAlarm() on
- // other iterators. OnShutdown() should not call UnregisterAlarm()
- // on self because by definition the iterator is not valid any more.
- i->second->OnShutdown(this);
- erase_it = i;
- ++i;
- alarm_map_.erase(erase_it);
- }
-}
-
-EpollServer::~EpollServer() {
- DCHECK_EQ(in_shutdown_, false);
- in_shutdown_ = true;
-#ifdef EPOLL_SERVER_EVENT_TRACING
- LOG(INFO) << "\n" << event_recorder_;
-#endif
- VLOG(2) << "Shutting down epoll server ";
- CleanupFDToCBMap();
-
- LIST_INIT(&ready_list_);
- LIST_INIT(&tmp_list_);
-
- CleanupTimeToAlarmCBMap();
-
- close(read_fd_);
- close(write_fd_);
- close(epoll_fd_);
-}
-
-// Whether a CBAandEventMask is on the ready list is determined by a non-NULL
-// le_prev pointer (le_next being NULL indicates end of list).
-inline void EpollServer::AddToReadyList(CBAndEventMask* cb_and_mask) {
- if (cb_and_mask->entry.le_prev == NULL) {
- LIST_INSERT_HEAD(&ready_list_, cb_and_mask, entry);
- ++ready_list_size_;
- }
-}
-
-inline void EpollServer::RemoveFromReadyList(
- const CBAndEventMask& cb_and_mask) {
- if (cb_and_mask.entry.le_prev != NULL) {
- LIST_REMOVE(&cb_and_mask, entry);
- // Clean up all the ready list states. Don't bother with the other fields
- // as they are initialized when the CBAandEventMask is added to the ready
- // list. This saves a few cycles in the inner loop.
- cb_and_mask.entry.le_prev = NULL;
- --ready_list_size_;
- if (ready_list_size_ == 0) {
- DCHECK(ready_list_.lh_first == NULL);
- DCHECK(tmp_list_.lh_first == NULL);
- }
- }
-}
-
-void EpollServer::RegisterFD(int fd, CB* cb, int event_mask) {
- CHECK(cb);
- VLOG(3) << "RegisterFD fd=" << fd << " event_mask=" << event_mask;
- FDToCBMap::iterator fd_i = cb_map_.find(CBAndEventMask(NULL, 0, fd));
- if (cb_map_.end() != fd_i) {
- // do we just abort, or do we just unregister the other guy?
- // for now, lets just unregister the other guy.
-
- // unregister any callback that may already be registered for this FD.
- CB* other_cb = fd_i->cb;
- if (other_cb) {
- // Must remove from the ready list before erasing.
- RemoveFromReadyList(*fd_i);
- other_cb->OnUnregistration(fd, true);
- ModFD(fd, event_mask);
- } else {
- // already unregistered, so just recycle the node.
- AddFD(fd, event_mask);
- }
- fd_i->cb = cb;
- fd_i->event_mask = event_mask;
- fd_i->events_to_fake = 0;
- } else {
- AddFD(fd, event_mask);
- cb_map_.insert(CBAndEventMask(cb, event_mask, fd));
- }
-
-
- // set the FD to be non-blocking.
- SetNonblocking(fd);
-
- cb->OnRegistration(this, fd, event_mask);
-}
-
-int EpollServer::GetFlags(int fd) {
- return fcntl(fd, F_GETFL, 0);
-}
-
-void EpollServer::SetNonblocking(int fd) {
- int flags = GetFlags(fd);
- if (flags == -1) {
- int saved_errno = errno;
- char buf[kErrorBufferSize];
- LOG(FATAL) << "Error " << saved_errno
- << " doing fcntl(" << fd << ", F_GETFL, 0): "
- << strerror_r(saved_errno, buf, sizeof(buf));
- }
- if (!(flags & O_NONBLOCK)) {
- int saved_flags = flags;
- flags = SetFlags(fd, flags | O_NONBLOCK);
- if (flags == -1) {
- // bad.
- int saved_errno = errno;
- char buf[kErrorBufferSize];
- LOG(FATAL) << "Error " << saved_errno
- << " doing fcntl(" << fd << ", F_SETFL, " << saved_flags << "): "
- << strerror_r(saved_errno, buf, sizeof(buf));
- }
- }
-}
-
-int EpollServer::epoll_wait_impl(int epfd,
- struct epoll_event* events,
- int max_events,
- int timeout_in_ms) {
- return epoll_wait(epfd, events, max_events, timeout_in_ms);
-}
-
-void EpollServer::RegisterFDForWrite(int fd, CB* cb) {
- RegisterFD(fd, cb, EPOLLOUT);
-}
-
-void EpollServer::RegisterFDForReadWrite(int fd, CB* cb) {
- RegisterFD(fd, cb, EPOLLIN | EPOLLOUT);
-}
-
-void EpollServer::RegisterFDForRead(int fd, CB* cb) {
- RegisterFD(fd, cb, EPOLLIN);
-}
-
-void EpollServer::UnregisterFD(int fd) {
- FDToCBMap::iterator fd_i = cb_map_.find(CBAndEventMask(NULL, 0, fd));
- if (cb_map_.end() == fd_i || fd_i->cb == NULL) {
- // Doesn't exist in server, or has gone through UnregisterFD once and still
- // inside the callchain of OnEvent.
- return;
- }
-#ifdef EPOLL_SERVER_EVENT_TRACING
- event_recorder_.RecordUnregistration(fd);
-#endif
- CB* cb = fd_i->cb;
- // Since the links are embedded within the struct, we must remove it from the
- // list before erasing it from the hash_set.
- RemoveFromReadyList(*fd_i);
- DelFD(fd);
- cb->OnUnregistration(fd, false);
- // fd_i->cb is NULL if that fd is unregistered inside the callchain of
- // OnEvent. Since the EpollServer needs a valid CBAndEventMask after OnEvent
- // returns in order to add it to the ready list, we cannot have UnregisterFD
- // erase the entry if it is in use. Thus, a NULL fd_i->cb is used as a
- // condition that tells the EpollServer that this entry is unused at a later
- // point.
- if (!fd_i->in_use) {
- cb_map_.erase(fd_i);
- } else {
- // Remove all trace of the registration, and just keep the node alive long
- // enough so the code that calls OnEvent doesn't have to worry about
- // figuring out whether the CBAndEventMask is valid or not.
- fd_i->cb = NULL;
- fd_i->event_mask = 0;
- fd_i->events_to_fake = 0;
- }
-}
-
-void EpollServer::ModifyCallback(int fd, int event_mask) {
- ModifyFD(fd, ~0, event_mask);
-}
-
-void EpollServer::StopRead(int fd) {
- ModifyFD(fd, EPOLLIN, 0);
-}
-
-void EpollServer::StartRead(int fd) {
- ModifyFD(fd, 0, EPOLLIN);
-}
-
-void EpollServer::StopWrite(int fd) {
- ModifyFD(fd, EPOLLOUT, 0);
-}
-
-void EpollServer::StartWrite(int fd) {
- ModifyFD(fd, 0, EPOLLOUT);
-}
-
-void EpollServer::HandleEvent(int fd, int event_mask) {
-#ifdef EPOLL_SERVER_EVENT_TRACING
- event_recorder_.RecordEpollEvent(fd, event_mask);
-#endif
- FDToCBMap::iterator fd_i = cb_map_.find(CBAndEventMask(NULL, 0, fd));
- if (fd_i == cb_map_.end() || fd_i->cb == NULL) {
- // Ignore the event.
- // This could occur if epoll() returns a set of events, and
- // while processing event A (earlier) we removed the callback
- // for event B (and are now processing event B).
- return;
- }
- fd_i->events_asserted = event_mask;
- CBAndEventMask* cb_and_mask = const_cast<CBAndEventMask*>(&*fd_i);
- AddToReadyList(cb_and_mask);
-}
-
-class TrueFalseGuard {
- public:
- explicit TrueFalseGuard(bool* guarded_bool) : guarded_bool_(guarded_bool) {
- DCHECK(guarded_bool_ != NULL);
- DCHECK(*guarded_bool_ == false);
- *guarded_bool_ = true;
- }
- ~TrueFalseGuard() {
- *guarded_bool_ = false;
- }
- private:
- bool* guarded_bool_;
-};
-
-void EpollServer::WaitForEventsAndExecuteCallbacks() {
- if (in_wait_for_events_and_execute_callbacks_) {
- LOG(DFATAL) <<
- "Attempting to call WaitForEventsAndExecuteCallbacks"
- " when an ancestor to the current function is already"
- " WaitForEventsAndExecuteCallbacks!";
- // The line below is actually tested, but in coverage mode,
- // we never see it.
- return; // COV_NF_LINE
- }
- TrueFalseGuard recursion_guard(&in_wait_for_events_and_execute_callbacks_);
- if (alarm_map_.empty()) {
- // no alarms, this is business as usual.
- WaitForEventsAndCallHandleEvents(timeout_in_us_,
- events_,
- events_size_);
- recorded_now_in_us_ = 0;
- return;
- }
-
- // store the 'now'. If we recomputed 'now' every iteration
- // down below, then we might never exit that loop-- any
- // long-running alarms might install other long-running
- // alarms, etc. By storing it here now, we ensure that
- // a more reasonable amount of work is done here.
- int64 now_in_us = NowInUsec();
-
- // Get the first timeout from the alarm_map where it is
- // stored in absolute time.
- int64 next_alarm_time_in_us = alarm_map_.begin()->first;
- VLOG(4) << "next_alarm_time = " << next_alarm_time_in_us
- << " now = " << now_in_us
- << " timeout_in_us = " << timeout_in_us_;
-
- int64 wait_time_in_us;
- int64 alarm_timeout_in_us = next_alarm_time_in_us - now_in_us;
-
- // If the next alarm is sooner than the default timeout, or if there is no
- // timeout (timeout_in_us_ == -1), wake up when the alarm should fire.
- // Otherwise use the default timeout.
- if (alarm_timeout_in_us < timeout_in_us_ || timeout_in_us_ < 0) {
- wait_time_in_us = std::max(alarm_timeout_in_us, static_cast<int64>(0));
- } else {
- wait_time_in_us = timeout_in_us_;
- }
-
- VLOG(4) << "wait_time_in_us = " << wait_time_in_us;
-
- // wait for events.
-
- WaitForEventsAndCallHandleEvents(wait_time_in_us,
- events_,
- events_size_);
- CallAndReregisterAlarmEvents();
- recorded_now_in_us_ = 0;
-}
-
-void EpollServer::SetFDReady(int fd, int events_to_fake) {
- FDToCBMap::iterator fd_i = cb_map_.find(CBAndEventMask(NULL, 0, fd));
- if (cb_map_.end() != fd_i && fd_i->cb != NULL) {
- // This const_cast is necessary for LIST_HEAD_INSERT to work. Declaring
- // entry mutable is insufficient because LIST_HEAD_INSERT assigns the
- // forward pointer of the list head to the current cb_and_mask, and the
- // compiler complains that it can't assign a const T* to a T*.
- CBAndEventMask* cb_and_mask = const_cast<CBAndEventMask*>(&*fd_i);
- // Note that there is no clearly correct behavior here when
- // cb_and_mask->events_to_fake != 0 and this function is called.
- // Of the two operations:
- // cb_and_mask->events_to_fake = events_to_fake
- // cb_and_mask->events_to_fake |= events_to_fake
- // the first was picked because it discourages users from calling
- // SetFDReady repeatedly to build up the correct event set as it is more
- // efficient to call SetFDReady once with the correct, final mask.
- cb_and_mask->events_to_fake = events_to_fake;
- AddToReadyList(cb_and_mask);
- }
-}
-
-void EpollServer::SetFDNotReady(int fd) {
- FDToCBMap::iterator fd_i = cb_map_.find(CBAndEventMask(NULL, 0, fd));
- if (cb_map_.end() != fd_i) {
- RemoveFromReadyList(*fd_i);
- }
-}
-
-bool EpollServer::IsFDReady(int fd) const {
- FDToCBMap::const_iterator fd_i = cb_map_.find(CBAndEventMask(NULL, 0, fd));
- return (cb_map_.end() != fd_i &&
- fd_i->cb != NULL &&
- fd_i->entry.le_prev != NULL);
-}
-
-void EpollServer::VerifyReadyList() const {
- int count = 0;
- CBAndEventMask* cur = ready_list_.lh_first;
- for (; cur; cur = cur->entry.le_next) {
- ++count;
- }
- for (cur = tmp_list_.lh_first; cur; cur = cur->entry.le_next) {
- ++count;
- }
- CHECK_EQ(ready_list_size_, count) << "Ready list size does not match count";
-}
-
-void EpollServer::RegisterAlarm(int64 timeout_time_in_us, AlarmCB* ac) {
- CHECK(ac);
- if (ContainsAlarm(ac)) {
- LOG(FATAL) << "Alarm already exists " << ac;
- }
- VLOG(4) << "RegisteringAlarm at : " << timeout_time_in_us;
-
- TimeToAlarmCBMap::iterator alarm_iter =
- alarm_map_.insert(std::make_pair(timeout_time_in_us, ac));
-
- all_alarms_.insert(ac);
- // Pass the iterator to the EpollAlarmCallbackInterface.
- ac->OnRegistration(alarm_iter, this);
-}
-
-// Unregister a specific alarm callback: iterator_token must be a
-// valid iterator. The caller must ensure the validity of the iterator.
-void EpollServer::UnregisterAlarm(const AlarmRegToken& iterator_token) {
- AlarmCB* cb = iterator_token->second;
- alarm_map_.erase(iterator_token);
- all_alarms_.erase(cb);
- cb->OnUnregistration();
-}
-
-int EpollServer::NumFDsRegistered() const {
- DCHECK_GE(cb_map_.size(), 1u);
- // Omit the internal FD (read_fd_)
- return cb_map_.size() - 1;
-}
-
-void EpollServer::Wake() {
- char data = 'd'; // 'd' is for data. It's good enough for me.
- int rv = write(write_fd_, &data, 1);
- DCHECK_EQ(rv, 1);
-}
-
-int64 EpollServer::NowInUsec() const {
- return base::Time::Now().ToInternalValue();
-}
-
-int64 EpollServer::ApproximateNowInUsec() const {
- if (recorded_now_in_us_ != 0) {
- return recorded_now_in_us_;
- }
- return this->NowInUsec();
-}
-
-std::string EpollServer::EventMaskToString(int event_mask) {
- std::string s;
- if (event_mask & EPOLLIN) s += "EPOLLIN ";
- if (event_mask & EPOLLPRI) s += "EPOLLPRI ";
- if (event_mask & EPOLLOUT) s += "EPOLLOUT ";
- if (event_mask & EPOLLRDNORM) s += "EPOLLRDNORM ";
- if (event_mask & EPOLLRDBAND) s += "EPOLLRDBAND ";
- if (event_mask & EPOLLWRNORM) s += "EPOLLWRNORM ";
- if (event_mask & EPOLLWRBAND) s += "EPOLLWRBAND ";
- if (event_mask & EPOLLMSG) s += "EPOLLMSG ";
- if (event_mask & EPOLLERR) s += "EPOLLERR ";
- if (event_mask & EPOLLHUP) s += "EPOLLHUP ";
- if (event_mask & EPOLLONESHOT) s += "EPOLLONESHOT ";
- if (event_mask & EPOLLET) s += "EPOLLET ";
- return s;
-}
-
-void EpollServer::LogStateOnCrash() {
- LOG(ERROR) << "----------------------Epoll Server---------------------------";
- LOG(ERROR) << "Epoll server " << this << " polling on fd " << epoll_fd_;
- LOG(ERROR) << "timeout_in_us_: " << timeout_in_us_;
-
- // Log sessions with alarms.
- LOG(ERROR) << alarm_map_.size() << " alarms registered.";
- for (TimeToAlarmCBMap::iterator it = alarm_map_.begin();
- it != alarm_map_.end();
- ++it) {
- const bool skipped =
- alarms_reregistered_and_should_be_skipped_.find(it->second)
- != alarms_reregistered_and_should_be_skipped_.end();
- LOG(ERROR) << "Alarm " << it->second << " registered at time " << it->first
- << " and should be skipped = " << skipped;
- }
-
- LOG(ERROR) << cb_map_.size() << " fd callbacks registered.";
- for (FDToCBMap::iterator it = cb_map_.begin();
- it != cb_map_.end();
- ++it) {
- LOG(ERROR) << "fd: " << it->fd << " with mask " << it->event_mask
- << " registered with cb: " << it->cb;
- }
- LOG(ERROR) << "----------------------/Epoll Server--------------------------";
-}
-
-
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-void EpollServer::DelFD(int fd) const {
- struct epoll_event ee;
- memset(&ee, 0, sizeof(ee));
-#ifdef EPOLL_SERVER_EVENT_TRACING
- event_recorder_.RecordFDMaskEvent(fd, 0, "DelFD");
-#endif
- if (epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd, &ee)) {
- int saved_errno = errno;
- char buf[kErrorBufferSize];
- LOG(FATAL) << "Epoll set removal error for fd " << fd << ": "
- << strerror_r(saved_errno, buf, sizeof(buf));
- }
-}
-
-////////////////////////////////////////
-
-void EpollServer::AddFD(int fd, int event_mask) const {
- struct epoll_event ee;
- memset(&ee, 0, sizeof(ee));
- ee.events = event_mask | EPOLLERR | EPOLLHUP;
- ee.data.fd = fd;
-#ifdef EPOLL_SERVER_EVENT_TRACING
- event_recorder_.RecordFDMaskEvent(fd, ee.events, "AddFD");
-#endif
- if (epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd, &ee)) {
- int saved_errno = errno;
- char buf[kErrorBufferSize];
- LOG(FATAL) << "Epoll set insertion error for fd " << fd << ": "
- << strerror_r(saved_errno, buf, sizeof(buf));
- }
-}
-
-////////////////////////////////////////
-
-void EpollServer::ModFD(int fd, int event_mask) const {
- struct epoll_event ee;
- memset(&ee, 0, sizeof(ee));
- ee.events = event_mask | EPOLLERR | EPOLLHUP;
- ee.data.fd = fd;
-#ifdef EPOLL_SERVER_EVENT_TRACING
- event_recorder_.RecordFDMaskEvent(fd, ee.events, "ModFD");
-#endif
- VLOG(3) << "modifying fd= " << fd << " "
- << EventMaskToString(ee.events);
- if (epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd, &ee)) {
- int saved_errno = errno;
- char buf[kErrorBufferSize];
- LOG(FATAL) << "Epoll set modification error for fd " << fd << ": "
- << strerror_r(saved_errno, buf, sizeof(buf));
- }
-}
-
-////////////////////////////////////////
-
-void EpollServer::ModifyFD(int fd, int remove_event, int add_event) {
- FDToCBMap::iterator fd_i = cb_map_.find(CBAndEventMask(NULL, 0, fd));
- if (cb_map_.end() == fd_i) {
- VLOG(2) << "Didn't find the fd " << fd << "in internal structures";
- return;
- }
-
- if (fd_i->cb != NULL) {
- int & event_mask = fd_i->event_mask;
- VLOG(3) << "fd= " << fd
- << " event_mask before: " << EventMaskToString(event_mask);
- event_mask &= ~remove_event;
- event_mask |= add_event;
-
- VLOG(3) << " event_mask after: " << EventMaskToString(event_mask);
-
- ModFD(fd, event_mask);
-
- fd_i->cb->OnModification(fd, event_mask);
- }
-}
-
-void EpollServer::WaitForEventsAndCallHandleEvents(int64 timeout_in_us,
- struct epoll_event events[],
- int events_size) {
- if (timeout_in_us == 0 || ready_list_.lh_first != NULL) {
- // If ready list is not empty, then don't sleep at all.
- timeout_in_us = 0;
- } else if (timeout_in_us < 0) {
- LOG(INFO) << "Negative epoll timeout: " << timeout_in_us
- << "us; epoll will wait forever for events.";
- // If timeout_in_us is < 0 we are supposed to Wait forever. This means we
- // should set timeout_in_us to -1000 so we will
- // Wait(-1000/1000) == Wait(-1) == Wait forever.
- timeout_in_us = -1000;
- } else {
- // If timeout is specified, and the ready list is empty.
- if (timeout_in_us < 1000) {
- timeout_in_us = 1000;
- }
- }
- const int timeout_in_ms = timeout_in_us / 1000;
- int nfds = epoll_wait_impl(epoll_fd_,
- events,
- events_size,
- timeout_in_ms);
- VLOG(3) << "nfds=" << nfds;
-
-#ifdef EPOLL_SERVER_EVENT_TRACING
- event_recorder_.RecordEpollWaitEvent(timeout_in_ms, nfds);
-#endif
-
- // If you're wondering why the NowInUsec() is recorded here, the answer is
- // simple: If we did it before the epoll_wait_impl, then the max error for
- // the ApproximateNowInUs() call would be as large as the maximum length of
- // epoll_wait, which can be arbitrarily long. Since this would make
- // ApproximateNowInUs() worthless, we instead record the time -after- we've
- // done epoll_wait, which guarantees that the maximum error is the amount of
- // time it takes to process all the events generated by epoll_wait.
- recorded_now_in_us_ = NowInUsec();
- if (nfds > 0) {
- for (int i = 0; i < nfds; ++i) {
- int event_mask = events[i].events;
- int fd = events[i].data.fd;
- HandleEvent(fd, event_mask);
- }
- } else if (nfds < 0) {
- // Catch interrupted syscall and just ignore it and move on.
- if (errno != EINTR && errno != 0) {
- int saved_errno = errno;
- char buf[kErrorBufferSize];
- LOG(FATAL) << "Error " << saved_errno << " in epoll_wait: "
- << strerror_r(saved_errno, buf, sizeof(buf));
- }
- }
-
- // Now run through the ready list.
- if (ready_list_.lh_first) {
- CallReadyListCallbacks();
- }
-}
-
-void EpollServer::CallReadyListCallbacks() {
- // Check pre-conditions.
- DCHECK(tmp_list_.lh_first == NULL);
- // Swap out the ready_list_ into the tmp_list_ before traversing the list to
- // enable SetFDReady() to just push new items into the ready_list_.
- std::swap(ready_list_.lh_first, tmp_list_.lh_first);
- if (tmp_list_.lh_first) {
- tmp_list_.lh_first->entry.le_prev = &tmp_list_.lh_first;
- EpollEvent event(0, false);
- while (tmp_list_.lh_first != NULL) {
- DCHECK_GT(ready_list_size_, 0);
- CBAndEventMask* cb_and_mask = tmp_list_.lh_first;
- RemoveFromReadyList(*cb_and_mask);
-
- event.out_ready_mask = 0;
- event.in_events =
- cb_and_mask->events_asserted | cb_and_mask->events_to_fake;
- // TODO(fenix): get rid of the two separate fields in cb_and_mask.
- cb_and_mask->events_asserted = 0;
- cb_and_mask->events_to_fake = 0;
- {
- // OnEvent() may call UnRegister, so we set in_use, here. Any
- // UnRegister call will now simply set the cb to NULL instead of
- // invalidating the cb_and_mask object (by deleting the object in the
- // map to which cb_and_mask refers)
- TrueFalseGuard in_use_guard(&(cb_and_mask->in_use));
- cb_and_mask->cb->OnEvent(cb_and_mask->fd, &event);
- }
-
- // Since OnEvent may have called UnregisterFD, we must check here that
- // the callback is still valid. If it isn't, then UnregisterFD *was*
- // called, and we should now get rid of the object.
- if (cb_and_mask->cb == NULL) {
- cb_map_.erase(*cb_and_mask);
- } else if (event.out_ready_mask != 0) {
- cb_and_mask->events_to_fake = event.out_ready_mask;
- AddToReadyList(cb_and_mask);
- }
- }
- }
- DCHECK(tmp_list_.lh_first == NULL);
-}
-
-void EpollServer::CallAndReregisterAlarmEvents() {
- int64 now_in_us = recorded_now_in_us_;
- DCHECK_NE(0, recorded_now_in_us_);
-
- TimeToAlarmCBMap::iterator erase_it;
-
- // execute alarms.
- for (TimeToAlarmCBMap::iterator i = alarm_map_.begin();
- i != alarm_map_.end();
- ) {
- if (i->first > now_in_us) {
- break;
- }
- AlarmCB* cb = i->second;
- // Execute the OnAlarm() only if we did not register
- // it in this loop itself.
- const bool added_in_this_round =
- alarms_reregistered_and_should_be_skipped_.find(cb)
- != alarms_reregistered_and_should_be_skipped_.end();
- if (added_in_this_round) {
- ++i;
- continue;
- }
- all_alarms_.erase(cb);
- const int64 new_timeout_time_in_us = cb->OnAlarm();
-
- erase_it = i;
- ++i;
- alarm_map_.erase(erase_it);
-
- if (new_timeout_time_in_us > 0) {
- // We add to hash_set only if the new timeout is <= now_in_us.
- // if timeout is > now_in_us then we have no fear that this alarm
- // can be reexecuted in this loop, and hence we do not need to
- // worry about a recursive loop.
- DVLOG(3) << "Reregistering alarm "
- << " " << cb
- << " " << new_timeout_time_in_us
- << " " << now_in_us;
- if (new_timeout_time_in_us <= now_in_us) {
- alarms_reregistered_and_should_be_skipped_.insert(cb);
- }
- RegisterAlarm(new_timeout_time_in_us, cb);
- }
- }
- alarms_reregistered_and_should_be_skipped_.clear();
-}
-
-EpollAlarm::EpollAlarm() : eps_(NULL), registered_(false) {
-}
-
-EpollAlarm::~EpollAlarm() {
- UnregisterIfRegistered();
-}
-
-int64 EpollAlarm::OnAlarm() {
- registered_ = false;
- return 0;
-}
-
-void EpollAlarm::OnRegistration(const EpollServer::AlarmRegToken& token,
- EpollServer* eps) {
- DCHECK_EQ(false, registered_);
-
- token_ = token;
- eps_ = eps;
- registered_ = true;
-}
-
-void EpollAlarm::OnUnregistration() {
- registered_ = false;
-}
-
-void EpollAlarm::OnShutdown(EpollServer* eps) {
- registered_ = false;
- eps_ = NULL;
-}
-
-// If the alarm was registered, unregister it.
-void EpollAlarm::UnregisterIfRegistered() {
- if (!registered_) {
- return;
- }
- eps_->UnregisterAlarm(token_);
-}
-
-} // namespace net
diff --git a/net/tools/flip_server/epoll_server.h b/net/tools/flip_server/epoll_server.h
deleted file mode 100644
index 2fb7c62..0000000
--- a/net/tools/flip_server/epoll_server.h
+++ /dev/null
@@ -1,1054 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_EPOLL_SERVER_H_
-#define NET_TOOLS_FLIP_SERVER_EPOLL_SERVER_H_
-
-#include <fcntl.h>
-#include <sys/queue.h>
-#include <map>
-#include <string>
-#include <utility>
-#include <set>
-#include <vector>
-
-// #define EPOLL_SERVER_EVENT_TRACING 1
-//
-// Defining EPOLL_SERVER_EVENT_TRACING
-// causes code to exist which didn't before.
-// This code tracks each event generated by the epollserver,
-// as well as providing a per-fd-registered summary of
-// events. Note that enabling this code vastly slows
-// down operations, and uses substantially more
-// memory. For these reasons, it should only be enabled when doing
-// developer debugging at his/her workstation.
-//
-// A structure called 'EventRecorder' will exist when
-// the macro is defined. See the EventRecorder class interface
-// within the EpollServer class for more details.
-#ifdef EPOLL_SERVER_EVENT_TRACING
-#include <ostream>
-#include "base/logging.h"
-#endif
-
-#include "base/basictypes.h"
-#include "base/compiler_specific.h"
-#include "base/containers/hash_tables.h"
-#include "base/memory/scoped_ptr.h"
-#include <sys/epoll.h>
-
-namespace net {
-
-class EpollServer;
-class EpollAlarmCallbackInterface;
-class ReadPipeCallback;
-
-struct EpollEvent {
- EpollEvent(int events, bool is_epoll_wait)
- : in_events(events),
- out_ready_mask(0) {
- }
-
- int in_events; // incoming events
- int out_ready_mask; // the new event mask for ready list (0 means don't
- // get on the ready list). This field is always
- // initialized to 0 when the event is passed to
- // OnEvent.
-};
-
-// Callbacks which go into EpollServers are expected to derive from this class.
-class EpollCallbackInterface {
- public:
- // Summary:
- // Called when the callback is registered into a EpollServer.
- // Args:
- // eps - the poll server into which this callback was registered
- // fd - the file descriptor which was registered
- // event_mask - the event mask (composed of EPOLLIN, EPOLLOUT, etc)
- // which was registered (and will initially be used
- // in the epoll() calls)
- virtual void OnRegistration(EpollServer* eps, int fd, int event_mask) = 0;
-
- // Summary:
- // Called when the event_mask is modified (for a file-descriptor)
- // Args:
- // fd - the file descriptor which was registered
- // event_mask - the event mask (composed of EPOLLIN, EPOLLOUT, etc)
- // which was is now curren (and will be used
- // in subsequent epoll() calls)
- virtual void OnModification(int fd, int event_mask) = 0;
-
- // Summary:
- // Called whenever an event occurs on the file-descriptor.
- // This is where the bulk of processing is expected to occur.
- // Args:
- // fd - the file descriptor which was registered
- // event - a struct that contains the event mask (composed of EPOLLIN,
- // EPOLLOUT, etc), a flag that indicates whether this is a true
- // epoll_wait event vs one from the ready list, and an output
- // parameter for OnEvent to inform the EpollServer whether to put
- // this fd on the ready list.
- virtual void OnEvent(int fd, EpollEvent* event) = 0;
-
- // Summary:
- // Called when the file-descriptor is unregistered from the poll-server.
- // Args:
- // fd - the file descriptor which was registered, and of this call, is now
- // unregistered.
- // replaced - If true, this callback is being replaced by another, otherwise
- // it is simply being removed.
- virtual void OnUnregistration(int fd, bool replaced) = 0;
-
- // Summary:
- // Called when the epoll server is shutting down. This is different from
- // OnUnregistration because the subclass may want to clean up memory.
- // This is called in leiu of OnUnregistration.
- // Args:
- // fd - the file descriptor which was registered.
- virtual void OnShutdown(EpollServer* eps, int fd) = 0;
-
- virtual ~EpollCallbackInterface() {}
-
- protected:
- EpollCallbackInterface() {}
-};
-
-////////////////////////////////////////////////////////////////////////////////
-////////////////////////////////////////////////////////////////////////////////
-
-class EpollServer {
- public:
- typedef EpollAlarmCallbackInterface AlarmCB;
- typedef EpollCallbackInterface CB;
-
- typedef std::multimap<int64, AlarmCB*> TimeToAlarmCBMap;
- typedef TimeToAlarmCBMap::iterator AlarmRegToken;
-
- // Summary:
- // Constructor:
- // By default, we don't wait any amount of time for events, and
- // we suggest to the epoll-system that we're going to use on-the-order
- // of 1024 FDs.
- EpollServer();
-
- ////////////////////////////////////////
-
- // Destructor
- virtual ~EpollServer();
-
- ////////////////////////////////////////
-
- // Summary
- // Register a callback to be called whenever an event contained
- // in the set of events included in event_mask occurs on the
- // file-descriptor 'fd'
- //
- // Note that only one callback is allowed to be registered for
- // any specific file-decriptor.
- //
- // If a callback is registered for a file-descriptor which has already
- // been registered, then the previous callback is unregistered with
- // the 'replaced' flag set to true. I.e. the previous callback's
- // OnUnregistration() function is called like so:
- // OnUnregistration(fd, true);
- //
- // The epoll server does NOT take on ownership of the callback: the callback
- // creator is responsible for managing that memory.
- //
- // Args:
- // fd - a valid file-descriptor
- // cb - an instance of a subclass of EpollCallbackInterface
- // event_mask - a combination of (EPOLLOUT, EPOLLIN.. etc) indicating
- // the events for which the callback would like to be
- // called.
- virtual void RegisterFD(int fd, CB* cb, int event_mask);
-
- ////////////////////////////////////////
-
- // Summary:
- // A shortcut for RegisterFD which sets things up such that the
- // callback is called when 'fd' is available for writing.
- // Args:
- // fd - a valid file-descriptor
- // cb - an instance of a subclass of EpollCallbackInterface
- virtual void RegisterFDForWrite(int fd, CB* cb);
-
- ////////////////////////////////////////
-
- // Summary:
- // A shortcut for RegisterFD which sets things up such that the
- // callback is called when 'fd' is available for reading or writing.
- // Args:
- // fd - a valid file-descriptor
- // cb - an instance of a subclass of EpollCallbackInterface
- virtual void RegisterFDForReadWrite(int fd, CB* cb);
-
- ////////////////////////////////////////
-
- // Summary:
- // A shortcut for RegisterFD which sets things up such that the
- // callback is called when 'fd' is available for reading.
- // Args:
- // fd - a valid file-descriptor
- // cb - an instance of a subclass of EpollCallbackInterface
- virtual void RegisterFDForRead(int fd, CB* cb);
-
- ////////////////////////////////////////
-
- // Summary:
- // Removes the FD and the associated callback from the pollserver.
- // If the callback is registered with other FDs, they will continue
- // to be processed using the callback without modification.
- // If the file-descriptor specified is not registered in the
- // epoll_server, then nothing happens as a result of this call.
- // Args:
- // fd - the file-descriptor which should no-longer be monitored.
- virtual void UnregisterFD(int fd);
-
- ////////////////////////////////////////
-
- // Summary:
- // Modifies the event mask for the file-descriptor, replacing
- // the old event_mask with the new one specified here.
- // If the file-descriptor specified is not registered in the
- // epoll_server, then nothing happens as a result of this call.
- // Args:
- // fd - the fd whose event mask should be modified.
- // event_mask - the new event mask.
- virtual void ModifyCallback(int fd, int event_mask);
-
- ////////////////////////////////////////
-
- // Summary:
- // Modifies the event mask for the file-descriptor such that we
- // no longer request events when 'fd' is readable.
- // If the file-descriptor specified is not registered in the
- // epoll_server, then nothing happens as a result of this call.
- // Args:
- // fd - the fd whose event mask should be modified.
- virtual void StopRead(int fd);
-
- ////////////////////////////////////////
-
- // Summary:
- // Modifies the event mask for the file-descriptor such that we
- // request events when 'fd' is readable.
- // If the file-descriptor specified is not registered in the
- // epoll_server, then nothing happens as a result of this call.
- // Args:
- // fd - the fd whose event mask should be modified.
- virtual void StartRead(int fd);
-
- ////////////////////////////////////////
-
- // Summary:
- // Modifies the event mask for the file-descriptor such that we
- // no longer request events when 'fd' is writable.
- // If the file-descriptor specified is not registered in the
- // epoll_server, then nothing happens as a result of this call.
- // Args:
- // fd - the fd whose event mask should be modified.
- virtual void StopWrite(int fd);
-
- ////////////////////////////////////////
-
- // Summary:
- // Modifies the event mask for the file-descriptor such that we
- // request events when 'fd' is writable.
- // If the file-descriptor specified is not registered in the
- // epoll_server, then nothing happens as a result of this call.
- // Args:
- // fd - the fd whose event mask should be modified.
- virtual void StartWrite(int fd);
-
- ////////////////////////////////////////
-
- // Summary:
- // Looks up the callback associated with the file-desriptor 'fd'.
- // If a callback is associated with this file-descriptor, then
- // it's OnEvent() method is called with the file-descriptor 'fd',
- // and event_mask 'event_mask'
- //
- // If no callback is registered for this file-descriptor, nothing
- // will happen as a result of this call.
- //
- // This function is used internally by the EpollServer, but is
- // available publically so that events might be 'faked'. Calling
- // this function with an fd and event_mask is equivalent (as far
- // as the callback is concerned) to having a real event generated
- // by epoll (except, of course, that read(), etc won't necessarily
- // be able to read anything)
- // Args:
- // fd - the file-descriptor on which an event has occured.
- // event_mask - a bitmask representing the events which have occured
- // on/for this fd. This bitmask is composed of
- // POLLIN, POLLOUT, etc.
- //
- void HandleEvent(int fd, int event_mask);
-
- // Summary:
- // Call this when you want the pollserver to
- // wait for events and execute the callbacks associated with
- // the file-descriptors on which those events have occured.
- // Depending on the value of timeout_in_us_, this may or may
- // not return immediately. Please reference the set_timeout()
- // function for the specific behaviour.
- virtual void WaitForEventsAndExecuteCallbacks();
-
- // Summary:
- // When an fd is registered to use edge trigger notification, the ready
- // list can be used to simulate level trigger semantics. Edge trigger
- // registration doesn't send an initial event, and only rising edge (going
- // from blocked to unblocked) events are sent. A callback can put itself on
- // the ready list by calling SetFDReady() after calling RegisterFD(). The
- // OnEvent method of all callbacks associated with the fds on the ready
- // list will be called immediately after processing the events returned by
- // epoll_wait(). The fd is removed from the ready list before the
- // callback's OnEvent() method is invoked. To stay on the ready list, the
- // OnEvent() (or some function in that call chain) must call SetFDReady
- // again. When a fd is unregistered using UnregisterFD(), the fd is
- // automatically removed from the ready list.
- //
- // When the callback for a edge triggered fd hits the falling edge (about
- // to block, either because of it got an EAGAIN, or had a short read/write
- // operation), it should remove itself from the ready list using
- // SetFDNotReady() (since OnEvent cannot distinguish between invocation
- // from the ready list vs from a normal epoll event). All four ready list
- // methods are safe to be called within the context of the callbacks.
- //
- // Since the ready list invokes EpollCallbackInterface::OnEvent, only fds
- // that are registered with the EpollServer will be put on the ready list.
- // SetFDReady() and SetFDNotReady() will do nothing if the EpollServer
- // doesn't know about the fd passed in.
- //
- // Since the ready list cannot reliably determine proper set of events
- // which should be sent to the callback, SetFDReady() requests the caller
- // to provide the ready list with the event mask, which will be used later
- // when OnEvent() is invoked by the ready list. Hence, the event_mask
- // passedto SetFDReady() does not affect the actual epoll registration of
- // the fd with the kernel. If a fd is already put on the ready list, and
- // SetFDReady() is called again for that fd with a different event_mask,
- // the event_mask will be updated.
- virtual void SetFDReady(int fd, int events_to_fake);
-
- virtual void SetFDNotReady(int fd);
-
- // Summary:
- // IsFDReady(), ReadyListSize(), and VerifyReadyList are intended as
- // debugging tools and for writing unit tests.
- // ISFDReady() returns whether a fd is in the ready list.
- // ReadyListSize() returns the number of fds on the ready list.
- // VerifyReadyList() checks the consistency of internal data structure. It
- // will CHECK if it finds an error.
- virtual bool IsFDReady(int fd) const;
-
- size_t ReadyListSize() const { return ready_list_size_; }
-
- void VerifyReadyList() const;
-
- ////////////////////////////////////////
-
- // Summary:
- // Registers an alarm 'ac' to go off at time 'timeout_time_in_us'.
- // If the callback returns a positive number from its OnAlarm() function,
- // then the callback will be re-registered at that time, else the alarm
- // owner is responsible for freeing up memory.
- //
- // Important: A give AlarmCB* can not be registered again if it is already
- // registered. If a user wants to register a callback again it should first
- // unregister the previous callback before calling RegisterAlarm again.
- // Args:
- // timeout_time_in_us - the absolute time at which the alarm should go off
- // ac - the alarm which will be called.
- virtual void RegisterAlarm(int64 timeout_time_in_us, AlarmCB* ac);
-
- // Summary:
- // Registers an alarm 'ac' to go off at time: (ApproximateNowInUs() +
- // delta_in_us). While this is somewhat less accurate (see the description
- // for ApproximateNowInUs() to see how 'approximate'), the error is never
- // worse than the amount of time it takes to process all events in one
- // WaitForEvents. As with 'RegisterAlarm()', if the callback returns a
- // positive number from its OnAlarm() function, then the callback will be
- // re-registered at that time, else the alarm owner is responsible for
- // freeing up memory.
- // Note that this function is purely a convienence. The
- // same thing may be accomplished by using RegisterAlarm with
- // ApproximateNowInUs() directly.
- //
- // Important: A give AlarmCB* can not be registered again if it is already
- // registered. If a user wants to register a callback again it should first
- // unregister the previous callback before calling RegisterAlarm again.
- // Args:
- // delta_in_us - the delta in microseconds from the ApproximateTimeInUs() at
- // which point the alarm should go off.
- // ac - the alarm which will be called.
- void RegisterAlarmApproximateDelta(int64 delta_in_us, AlarmCB* ac) {
- RegisterAlarm(ApproximateNowInUsec() + delta_in_us, ac);
- }
-
- ////////////////////////////////////////
-
- // Summary:
- // Unregister the alarm referred to by iterator_token; Callers should
- // be warned that a token may have become already invalid when OnAlarm()
- // is called, was unregistered, or OnShutdown was called on that alarm.
- // Args:
- // iterator_token - iterator to the alarm callback to unregister.
- virtual void UnregisterAlarm(
- const EpollServer::AlarmRegToken& iterator_token);
-
- ////////////////////////////////////////
-
- // Summary:
- // returns the number of file-descriptors registered in this EpollServer.
- // Returns:
- // number of FDs registered (discounting the internal pipe used for Wake)
- virtual int NumFDsRegistered() const;
-
- // Summary:
- // Force the epoll server to wake up (by writing to an internal pipe).
- virtual void Wake();
-
- // Summary:
- // Wrapper around WallTimer's NowInUsec. We do this so that we can test
- // EpollServer without using the system clock (and can avoid the flakiness
- // that would ensue)
- // Returns:
- // the current time as number of microseconds since the Unix epoch.
- virtual int64 NowInUsec() const;
-
- // Summary:
- // Since calling NowInUsec() many thousands of times per
- // WaitForEventsAndExecuteCallbacks function call is, to say the least,
- // inefficient, we allow users to use an approximate time instead. The
- // time returned from this function is as accurate as NowInUsec() when
- // WaitForEventsAndExecuteCallbacks is not an ancestor of the caller's
- // callstack.
- // However, when WaitForEventsAndExecuteCallbacks -is- an ancestor, then
- // this function returns the time at which the
- // WaitForEventsAndExecuteCallbacks function started to process events or
- // alarms.
- //
- // Essentially, this function makes available a fast and mostly accurate
- // mechanism for getting the time for any function handling an event or
- // alarm. When functions which are not handling callbacks or alarms call
- // this function, they get the slow and "absolutely" accurate time.
- //
- // Users should be encouraged to use this function.
- // Returns:
- // the "approximate" current time as number of microseconds since the Unix
- // epoch.
- virtual int64 ApproximateNowInUsec() const;
-
- static std::string EventMaskToString(int event_mask);
-
- // Summary:
- // Logs the state of the epoll server with LOG(ERROR).
- void LogStateOnCrash();
-
- // Summary:
- // Set the timeout to the value specified.
- // If the timeout is set to a negative number,
- // WaitForEventsAndExecuteCallbacks() will only return when an event has
- // occured
- // If the timeout is set to zero,
- // WaitForEventsAndExecuteCallbacks() will return immediately
- // If the timeout is set to a positive number,
- // WaitForEventsAndExecuteCallbacks() will return when an event has
- // occured, or when timeout_in_us microseconds has elapsed, whichever
- // is first.
- // Args:
- // timeout_in_us - value specified depending on behaviour desired.
- // See above.
- void set_timeout_in_us(int64 timeout_in_us) {
- timeout_in_us_ = timeout_in_us;
- }
-
- ////////////////////////////////////////
-
- // Summary:
- // Accessor for the current value of timeout_in_us.
- int timeout_in_us() const { return timeout_in_us_; }
-
- // Summary:
- // Returns true when the EpollServer() is being destroyed.
- bool in_shutdown() const { return in_shutdown_; }
-
- bool ContainsAlarm(EpollAlarmCallbackInterface* alarm) const {
- return all_alarms_.find(alarm) != all_alarms_.end();
- }
-
- // Summary:
- // A function for implementing the ready list. It invokes OnEvent for each
- // of the fd in the ready list, and takes care of adding them back to the
- // ready list if the callback requests it (by checking that out_ready_mask
- // is non-zero).
- void CallReadyListCallbacks();
-
- protected:
- virtual int GetFlags(int fd);
- inline int SetFlags(int fd, int flags) {
- return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
- }
-
- virtual void SetNonblocking(int fd);
-
- // This exists here so that we can override this function in unittests
- // in order to make effective mock EpollServer objects.
- virtual int epoll_wait_impl(int epfd,
- struct epoll_event* events,
- int max_events,
- int timeout_in_ms);
-
- // this struct is used internally, and is never used by anything external
- // to this class. Some of its members are declared mutable to get around the
- // restriction imposed by hash_set. Since hash_set knows nothing about the
- // objects it stores, it has to assume that every bit of the object is used
- // in the hash function and equal_to comparison. Thus hash_set::iterator is a
- // const iterator. In this case, the only thing that must stay constant is
- // fd. Everything else are just along for the ride and changing them doesn't
- // compromise the hash_set integrity.
- struct CBAndEventMask {
- CBAndEventMask()
- : cb(NULL),
- fd(-1),
- event_mask(0),
- events_asserted(0),
- events_to_fake(0),
- in_use(false) {
- entry.le_next = NULL;
- entry.le_prev = NULL;
- }
-
- CBAndEventMask(EpollCallbackInterface* cb,
- int event_mask,
- int fd)
- : cb(cb), fd(fd), event_mask(event_mask), events_asserted(0),
- events_to_fake(0), in_use(false) {
- entry.le_next = NULL;
- entry.le_prev = NULL;
- }
-
- // Required operator for hash_set. Normally operator== should be a free
- // standing function. However, since CBAndEventMask is a protected type and
- // it will never be a base class, it makes no difference.
- bool operator==(const CBAndEventMask& cb_and_mask) const {
- return fd == cb_and_mask.fd;
- }
- // A callback. If the fd is unregistered inside the callchain of OnEvent,
- // the cb will be set to NULL.
- mutable EpollCallbackInterface* cb;
-
- mutable LIST_ENTRY(CBAndEventMask) entry;
- // file descriptor registered with the epoll server.
- int fd;
- // the current event_mask registered for this callback.
- mutable int event_mask;
- // the event_mask that was returned by epoll
- mutable int events_asserted;
- // the event_mask for the ready list to use to call OnEvent.
- mutable int events_to_fake;
- // toggle around calls to OnEvent to tell UnregisterFD to not erase the
- // iterator because HandleEvent is using it.
- mutable bool in_use;
- };
-
- // Custom hash function to be used by hash_set.
- struct CBAndEventMaskHash {
- size_t operator()(const CBAndEventMask& cb_and_eventmask) const {
- return static_cast<size_t>(cb_and_eventmask.fd);
- }
- };
-
- typedef base::hash_set<CBAndEventMask, CBAndEventMaskHash> FDToCBMap;
-
- // the following four functions are OS-specific, and are likely
- // to be changed in a subclass if the poll/select method is changed
- // from epoll.
-
- // Summary:
- // Deletes a file-descriptor from the set of FDs that should be
- // monitored with epoll.
- // Note that this only deals with modifying data relating -directly-
- // with the epoll call-- it does not modify any data within the
- // epoll_server.
- // Args:
- // fd - the file descriptor to-be-removed from the monitoring set
- virtual void DelFD(int fd) const;
-
- ////////////////////////////////////////
-
- // Summary:
- // Adds a file-descriptor to the set of FDs that should be
- // monitored with epoll.
- // Note that this only deals with modifying data relating -directly-
- // with the epoll call.
- // Args:
- // fd - the file descriptor to-be-added to the monitoring set
- // event_mask - the event mask (consisting of EPOLLIN, EPOLLOUT, etc
- // OR'd together) which will be associated with this
- // FD initially.
- virtual void AddFD(int fd, int event_mask) const;
-
- ////////////////////////////////////////
-
- // Summary:
- // Modifies a file-descriptor in the set of FDs that should be
- // monitored with epoll.
- // Note that this only deals with modifying data relating -directly-
- // with the epoll call.
- // Args:
- // fd - the file descriptor to-be-added to the monitoring set
- // event_mask - the event mask (consisting of EPOLLIN, EPOLLOUT, etc
- // OR'd together) which will be associated with this
- // FD after this call.
- virtual void ModFD(int fd, int event_mask) const;
-
- ////////////////////////////////////////
-
- // Summary:
- // Modified the event mask associated with an FD in the set of
- // data needed by epoll.
- // Events are removed before they are added, thus, if ~0 is put
- // in 'remove_event', whatever is put in 'add_event' will be
- // the new event mask.
- // If the file-descriptor specified is not registered in the
- // epoll_server, then nothing happens as a result of this call.
- // Args:
- // fd - the file descriptor whose event mask is to be modified
- // remove_event - the events which are to be removed from the current
- // event_mask
- // add_event - the events which are to be added to the current event_mask
- //
- //
- virtual void ModifyFD(int fd, int remove_event, int add_event);
-
- ////////////////////////////////////////
-
- // Summary:
- // Waits for events, and calls HandleEvents() for each
- // fd, event pair discovered to possibly have an event.
- // Note that a callback (B) may get a spurious event if
- // another callback (A) has closed a file-descriptor N, and
- // the callback (B) has a newly opened file-descriptor, which
- // also happens to be N.
- virtual void WaitForEventsAndCallHandleEvents(int64 timeout_in_us,
- struct epoll_event events[],
- int events_size);
-
-
-
- // Summary:
- // An internal function for implementing the ready list. It adds a fd's
- // CBAndEventMask to the ready list. If the fd is already on the ready
- // list, it is a no-op.
- void AddToReadyList(CBAndEventMask* cb_and_mask);
-
- // Summary:
- // An internal function for implementing the ready list. It remove a fd's
- // CBAndEventMask from the ready list. If the fd is not on the ready list,
- // it is a no-op.
- void RemoveFromReadyList(const CBAndEventMask& cb_and_mask);
-
- // Summary:
- // Calls any pending alarms that should go off and reregisters them if they
- // were recurring.
- virtual void CallAndReregisterAlarmEvents();
-
- // The file-descriptor created for epolling
- int epoll_fd_;
-
- // The mapping of file-descriptor to CBAndEventMasks
- FDToCBMap cb_map_;
-
- // Custom hash function to be used by hash_set.
- struct AlarmCBHash {
- size_t operator()(AlarmCB*const& p) const {
- return reinterpret_cast<size_t>(p);
- }
- };
-
-
- // TOOD(sushantj): Having this hash_set is avoidable. We currently have it
- // only so that we can enforce stringent checks that a caller can not register
- // the same alarm twice. One option is to have an implementation in which
- // this hash_set is used only in the debug mode.
- typedef base::hash_set<AlarmCB*, AlarmCBHash> AlarmCBMap;
- AlarmCBMap all_alarms_;
-
- TimeToAlarmCBMap alarm_map_;
-
- // The amount of time in microseconds that we'll wait before returning
- // from the WaitForEventsAndExecuteCallbacks() function.
- // If this is positive, wait that many microseconds.
- // If this is negative, wait forever, or for the first event that occurs
- // If this is zero, never wait for an event.
- int64 timeout_in_us_;
-
- // This is nonzero only after the invocation of epoll_wait_impl within
- // WaitForEventsAndCallHandleEvents and before the function
- // WaitForEventsAndExecuteCallbacks returns. At all other times, this is
- // zero. This enables us to have relatively accurate time returned from the
- // ApproximateNowInUs() function. See that function for more details.
- int64 recorded_now_in_us_;
-
- // This is used to implement CallAndReregisterAlarmEvents. This stores
- // all alarms that were reregistered because OnAlarm() returned a
- // value > 0 and the time at which they should be executed is less that
- // the current time. By storing such alarms in this map we ensure
- // that while calling CallAndReregisterAlarmEvents we do not call
- // OnAlarm on any alarm in this set. This ensures that we do not
- // go in an infinite loop.
- AlarmCBMap alarms_reregistered_and_should_be_skipped_;
-
- LIST_HEAD(ReadyList, CBAndEventMask) ready_list_;
- LIST_HEAD(TmpList, CBAndEventMask) tmp_list_;
- int ready_list_size_;
- // TODO(alyssar): make this into something that scales up.
- static const int events_size_ = 256;
- struct epoll_event events_[256];
-
-#ifdef EPOLL_SERVER_EVENT_TRACING
- struct EventRecorder {
- public:
- EventRecorder() : num_records_(0), record_threshold_(10000) {}
-
- ~EventRecorder() {
- Clear();
- }
-
- // When a number of events equals the record threshold,
- // the collected data summary for all FDs will be written
- // to LOG(INFO). Note that this does not include the
- // individual events (if you'reinterested in those, you'll
- // have to get at them programmatically).
- // After any such flushing to LOG(INFO) all events will
- // be cleared.
- // Note that the definition of an 'event' is a bit 'hazy',
- // as it includes the 'Unregistration' event, and perhaps
- // others.
- void set_record_threshold(int64 new_threshold) {
- record_threshold_ = new_threshold;
- }
-
- void Clear() {
- for (int i = 0; i < debug_events_.size(); ++i) {
- delete debug_events_[i];
- }
- debug_events_.clear();
- unregistered_fds_.clear();
- event_counts_.clear();
- }
-
- void MaybeRecordAndClear() {
- ++num_records_;
- if ((num_records_ > record_threshold_) &&
- (record_threshold_ > 0)) {
- LOG(INFO) << "\n" << *this;
- num_records_ = 0;
- Clear();
- }
- }
-
- void RecordFDMaskEvent(int fd, int mask, const char* function) {
- FDMaskOutput* fdmo = new FDMaskOutput(fd, mask, function);
- debug_events_.push_back(fdmo);
- MaybeRecordAndClear();
- }
-
- void RecordEpollWaitEvent(int timeout_in_ms,
- int num_events_generated) {
- EpollWaitOutput* ewo = new EpollWaitOutput(timeout_in_ms,
- num_events_generated);
- debug_events_.push_back(ewo);
- MaybeRecordAndClear();
- }
-
- void RecordEpollEvent(int fd, int event_mask) {
- Events& events_for_fd = event_counts_[fd];
- events_for_fd.AssignFromMask(event_mask);
- MaybeRecordAndClear();
- }
-
- friend ostream& operator<<(ostream& os, const EventRecorder& er) {
- for (int i = 0; i < er.unregistered_fds_.size(); ++i) {
- os << "fd: " << er.unregistered_fds_[i] << "\n";
- os << er.unregistered_fds_[i];
- }
- for (EventCountsMap::const_iterator i = er.event_counts_.begin();
- i != er.event_counts_.end();
- ++i) {
- os << "fd: " << i->first << "\n";
- os << i->second;
- }
- for (int i = 0; i < er.debug_events_.size(); ++i) {
- os << *(er.debug_events_[i]) << "\n";
- }
- return os;
- }
-
- void RecordUnregistration(int fd) {
- EventCountsMap::iterator i = event_counts_.find(fd);
- if (i != event_counts_.end()) {
- unregistered_fds_.push_back(i->second);
- event_counts_.erase(i);
- }
- MaybeRecordAndClear();
- }
-
- protected:
- class DebugOutput {
- public:
- friend ostream& operator<<(ostream& os, const DebugOutput& debug_output) {
- debug_output.OutputToStream(os);
- return os;
- }
- virtual void OutputToStream(ostream* os) const = 0;
- virtual ~DebugOutput() {}
- };
-
- class FDMaskOutput : public DebugOutput {
- public:
- FDMaskOutput(int fd, int mask, const char* function) :
- fd_(fd), mask_(mask), function_(function) {}
- virtual void OutputToStream(ostream* os) const {
- (*os) << "func: " << function_
- << "\tfd: " << fd_;
- if (mask_ != 0) {
- (*os) << "\tmask: " << EventMaskToString(mask_);
- }
- }
- int fd_;
- int mask_;
- const char* function_;
- };
-
- class EpollWaitOutput : public DebugOutput {
- public:
- EpollWaitOutput(int timeout_in_ms,
- int num_events_generated) :
- timeout_in_ms_(timeout_in_ms),
- num_events_generated_(num_events_generated) {}
- virtual void OutputToStream(ostream* os) const {
- (*os) << "timeout_in_ms: " << timeout_in_ms_
- << "\tnum_events_generated: " << num_events_generated_;
- }
- protected:
- int timeout_in_ms_;
- int num_events_generated_;
- };
-
- struct Events {
- Events() :
- epoll_in(0),
- epoll_pri(0),
- epoll_out(0),
- epoll_rdnorm(0),
- epoll_rdband(0),
- epoll_wrnorm(0),
- epoll_wrband(0),
- epoll_msg(0),
- epoll_err(0),
- epoll_hup(0),
- epoll_oneshot(0),
- epoll_et(0) {}
-
- void AssignFromMask(int event_mask) {
- if (event_mask & EPOLLIN) ++epoll_in;
- if (event_mask & EPOLLPRI) ++epoll_pri;
- if (event_mask & EPOLLOUT) ++epoll_out;
- if (event_mask & EPOLLRDNORM) ++epoll_rdnorm;
- if (event_mask & EPOLLRDBAND) ++epoll_rdband;
- if (event_mask & EPOLLWRNORM) ++epoll_wrnorm;
- if (event_mask & EPOLLWRBAND) ++epoll_wrband;
- if (event_mask & EPOLLMSG) ++epoll_msg;
- if (event_mask & EPOLLERR) ++epoll_err;
- if (event_mask & EPOLLHUP) ++epoll_hup;
- if (event_mask & EPOLLONESHOT) ++epoll_oneshot;
- if (event_mask & EPOLLET) ++epoll_et;
- };
-
- friend ostream& operator<<(ostream& os, const Events& ev) {
- if (ev.epoll_in) {
- os << "\t EPOLLIN: " << ev.epoll_in << "\n";
- }
- if (ev.epoll_pri) {
- os << "\t EPOLLPRI: " << ev.epoll_pri << "\n";
- }
- if (ev.epoll_out) {
- os << "\t EPOLLOUT: " << ev.epoll_out << "\n";
- }
- if (ev.epoll_rdnorm) {
- os << "\t EPOLLRDNORM: " << ev.epoll_rdnorm << "\n";
- }
- if (ev.epoll_rdband) {
- os << "\t EPOLLRDBAND: " << ev.epoll_rdband << "\n";
- }
- if (ev.epoll_wrnorm) {
- os << "\t EPOLLWRNORM: " << ev.epoll_wrnorm << "\n";
- }
- if (ev.epoll_wrband) {
- os << "\t EPOLLWRBAND: " << ev.epoll_wrband << "\n";
- }
- if (ev.epoll_msg) {
- os << "\t EPOLLMSG: " << ev.epoll_msg << "\n";
- }
- if (ev.epoll_err) {
- os << "\t EPOLLERR: " << ev.epoll_err << "\n";
- }
- if (ev.epoll_hup) {
- os << "\t EPOLLHUP: " << ev.epoll_hup << "\n";
- }
- if (ev.epoll_oneshot) {
- os << "\t EPOLLONESHOT: " << ev.epoll_oneshot << "\n";
- }
- if (ev.epoll_et) {
- os << "\t EPOLLET: " << ev.epoll_et << "\n";
- }
- return os;
- }
-
- unsigned int epoll_in;
- unsigned int epoll_pri;
- unsigned int epoll_out;
- unsigned int epoll_rdnorm;
- unsigned int epoll_rdband;
- unsigned int epoll_wrnorm;
- unsigned int epoll_wrband;
- unsigned int epoll_msg;
- unsigned int epoll_err;
- unsigned int epoll_hup;
- unsigned int epoll_oneshot;
- unsigned int epoll_et;
- };
-
- std::vector<DebugOutput*> debug_events_;
- std::vector<Events> unregistered_fds_;
- typedef base::hash_map<int, Events> EventCountsMap;
- EventCountsMap event_counts_;
- int64 num_records_;
- int64 record_threshold_;
- };
-
- void ClearEventRecords() {
- event_recorder_.Clear();
- }
- void WriteEventRecords(ostream* os) const {
- (*os) << event_recorder_;
- }
-
- mutable EventRecorder event_recorder_;
-
-#endif
-
- private:
- // Helper functions used in the destructor.
- void CleanupFDToCBMap();
- void CleanupTimeToAlarmCBMap();
-
- // The callback registered to the fds below. As the purpose of their
- // registration is to wake the epoll server it just clears the pipe and
- // returns.
- scoped_ptr<ReadPipeCallback> wake_cb_;
-
- // A pipe owned by the epoll server. The server will be registered to listen
- // on read_fd_ and can be woken by Wake() which writes to write_fd_.
- int read_fd_;
- int write_fd_;
-
- // This boolean is checked to see if it is false at the top of the
- // WaitForEventsAndExecuteCallbacks function. If not, then it either returns
- // without doing work, and logs to ERROR, or aborts the program (in
- // DEBUG mode). If so, then it sets the bool to true, does work, and
- // sets it back to false when done. This catches unwanted recursion.
- bool in_wait_for_events_and_execute_callbacks_;
-
- // Returns true when the EpollServer() is being destroyed.
- bool in_shutdown_;
-
- DISALLOW_COPY_AND_ASSIGN(EpollServer);
-};
-
-class EpollAlarmCallbackInterface {
- public:
- // Summary:
- // Called when an alarm times out. Invalidates an AlarmRegToken.
- // WARNING: If a token was saved to refer to an alarm callback, OnAlarm must
- // delete it, as the reference is no longer valid.
- // Returns:
- // the unix time (in microseconds) at which this alarm should be signaled
- // again, or 0 if the alarm should be removed.
- virtual int64 OnAlarm() = 0;
-
- // Summary:
- // Called when the an alarm is registered. Invalidates an AlarmRegToken.
- // Args:
- // token: the iterator to the the alarm registered in the alarm map.
- // WARNING: this token becomes invalid when the alarm fires, is
- // unregistered, or OnShutdown is called on that alarm.
- // eps: the epoll server the alarm is registered with.
- virtual void OnRegistration(const EpollServer::AlarmRegToken& token,
- EpollServer* eps) = 0;
-
- // Summary:
- // Called when the an alarm is unregistered.
- // WARNING: It is not valid to unregister a callback and then use the token
- // that was saved to refer to the callback.
- virtual void OnUnregistration() = 0;
-
- // Summary:
- // Called when the epoll server is shutting down.
- // Invalidates the AlarmRegToken that was given when this alarm was
- // registered.
- virtual void OnShutdown(EpollServer* eps) = 0;
-
- virtual ~EpollAlarmCallbackInterface() {}
-
- protected:
- EpollAlarmCallbackInterface() {}
-};
-
-// A simple alarm which unregisters itself on destruction.
-//
-// PLEASE NOTE:
-// Any classes overriding these functions must either call the implementation
-// of the parent class, or is must otherwise make sure that the 'registered_'
-// boolean and the token, 'token_', are updated appropriately.
-class EpollAlarm : public EpollAlarmCallbackInterface {
- public:
- EpollAlarm();
-
- virtual ~EpollAlarm();
-
- // Marks the alarm as unregistered and returns 0. The return value may be
- // safely ignored by subclasses.
- virtual int64 OnAlarm() OVERRIDE;
-
- // Marks the alarm as registered, and stores the token.
- virtual void OnRegistration(const EpollServer::AlarmRegToken& token,
- EpollServer* eps) OVERRIDE;
-
- // Marks the alarm as unregistered.
- virtual void OnUnregistration() OVERRIDE;
-
- // Marks the alarm as unregistered.
- virtual void OnShutdown(EpollServer* eps) OVERRIDE;
-
- // If the alarm was registered, unregister it.
- void UnregisterIfRegistered();
-
- bool registered() const { return registered_; }
-
- const EpollServer* eps() const { return eps_; }
-
- private:
- EpollServer::AlarmRegToken token_;
- EpollServer* eps_;
- bool registered_;
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_EPOLL_SERVER_H_
-
diff --git a/net/tools/flip_server/flip_in_mem_edsm_server.cc b/net/tools/flip_server/flip_in_mem_edsm_server.cc
index ce7ffb8..79f3e5b 100644
--- a/net/tools/flip_server/flip_in_mem_edsm_server.cc
+++ b/net/tools/flip_server/flip_in_mem_edsm_server.cc
@@ -15,6 +15,7 @@
#include "base/logging.h"
#include "base/synchronization/lock.h"
#include "base/timer/timer.h"
+#include "net/tools/balsa/split.h"
#include "net/tools/flip_server/acceptor_thread.h"
#include "net/tools/flip_server/constants.h"
#include "net/tools/flip_server/flip_config.h"
@@ -22,7 +23,6 @@
#include "net/tools/flip_server/sm_connection.h"
#include "net/tools/flip_server/sm_interface.h"
#include "net/tools/flip_server/spdy_interface.h"
-#include "net/tools/flip_server/split.h"
#include "net/tools/flip_server/streamer_interface.h"
using std::cout;
@@ -421,4 +421,3 @@ int main (int argc, char**argv)
close(pidfile_fd);
return 0;
}
-
diff --git a/net/tools/flip_server/http_interface.cc b/net/tools/flip_server/http_interface.cc
index 916ba51..78c42cc 100644
--- a/net/tools/flip_server/http_interface.cc
+++ b/net/tools/flip_server/http_interface.cc
@@ -4,8 +4,8 @@
#include "net/tools/flip_server/http_interface.h"
+#include "net/tools/balsa/balsa_frame.h"
#include "net/tools/dump_cache/url_utilities.h"
-#include "net/tools/flip_server/balsa_frame.h"
#include "net/tools/flip_server/flip_config.h"
#include "net/tools/flip_server/sm_connection.h"
#include "net/tools/flip_server/spdy_util.h"
diff --git a/net/tools/flip_server/http_interface.h b/net/tools/flip_server/http_interface.h
index 18e616d..867e342 100644
--- a/net/tools/flip_server/http_interface.h
+++ b/net/tools/flip_server/http_interface.h
@@ -8,8 +8,8 @@
#include <string>
#include "base/compiler_specific.h"
-#include "net/tools/flip_server/balsa_headers.h"
-#include "net/tools/flip_server/balsa_visitor_interface.h"
+#include "net/tools/balsa/balsa_headers.h"
+#include "net/tools/balsa/balsa_visitor_interface.h"
#include "net/tools/flip_server/output_ordering.h"
#include "net/tools/flip_server/sm_connection.h"
#include "net/tools/flip_server/sm_interface.h"
diff --git a/net/tools/flip_server/http_interface_test.cc b/net/tools/flip_server/http_interface_test.cc
index ba9b3aa..c6e3c64 100644
--- a/net/tools/flip_server/http_interface_test.cc
+++ b/net/tools/flip_server/http_interface_test.cc
@@ -9,9 +9,9 @@
#include "base/memory/scoped_ptr.h"
#include "base/stl_util.h"
#include "base/strings/string_piece.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "net/tools/flip_server/balsa_frame.h"
-#include "net/tools/flip_server/balsa_headers.h"
+#include "net/tools/balsa/balsa_enums.h"
+#include "net/tools/balsa/balsa_frame.h"
+#include "net/tools/balsa/balsa_headers.h"
#include "net/tools/flip_server/flip_config.h"
#include "net/tools/flip_server/flip_test_utils.h"
#include "net/tools/flip_server/mem_cache.h"
diff --git a/net/tools/flip_server/http_message_constants.h b/net/tools/flip_server/http_message_constants.h
deleted file mode 100644
index de700cc..0000000
--- a/net/tools/flip_server/http_message_constants.h
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_HTTP_MESSAGE_CONSTANTS_H__
-#define NET_TOOLS_FLIP_SERVER_HTTP_MESSAGE_CONSTANTS_H__
-
-namespace net {
-
-const char* get_http_status_message(int status_message);
-extern const int http_status_codes[];
-extern const int http_status_code_count;
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_HTTP_MESSAGE_CONSTANTS_H__
-
diff --git a/net/tools/flip_server/mem_cache.cc b/net/tools/flip_server/mem_cache.cc
index d1e0e58..42d9343 100644
--- a/net/tools/flip_server/mem_cache.cc
+++ b/net/tools/flip_server/mem_cache.cc
@@ -17,10 +17,10 @@
#include <string>
#include "base/strings/string_util.h"
+#include "net/tools/balsa/balsa_frame.h"
+#include "net/tools/balsa/balsa_headers.h"
#include "net/tools/dump_cache/url_to_filename_encoder.h"
#include "net/tools/dump_cache/url_utilities.h"
-#include "net/tools/flip_server/balsa_frame.h"
-#include "net/tools/flip_server/balsa_headers.h"
namespace {
// The directory where cache locates);
diff --git a/net/tools/flip_server/mem_cache.h b/net/tools/flip_server/mem_cache.h
index 300c84a..b059f02 100644
--- a/net/tools/flip_server/mem_cache.h
+++ b/net/tools/flip_server/mem_cache.h
@@ -10,8 +10,8 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "net/tools/flip_server/balsa_headers.h"
-#include "net/tools/flip_server/balsa_visitor_interface.h"
+#include "net/tools/balsa/balsa_headers.h"
+#include "net/tools/balsa/balsa_visitor_interface.h"
#include "net/tools/flip_server/constants.h"
namespace net {
diff --git a/net/tools/flip_server/mem_cache_test.cc b/net/tools/flip_server/mem_cache_test.cc
index d5601ac..59bc485 100644
--- a/net/tools/flip_server/mem_cache_test.cc
+++ b/net/tools/flip_server/mem_cache_test.cc
@@ -4,7 +4,7 @@
#include "net/tools/flip_server/mem_cache.h"
-#include "net/tools/flip_server/balsa_headers.h"
+#include "net/tools/balsa/balsa_headers.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace net {
diff --git a/net/tools/flip_server/noop_balsa_visitor.h b/net/tools/flip_server/noop_balsa_visitor.h
deleted file mode 100644
index 04f4aa6..0000000
--- a/net/tools/flip_server/noop_balsa_visitor.h
+++ /dev/null
@@ -1,60 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-//
-// Provides empty BalsaVisitorInterface overrides for convenience.
-// Intended to be used as a base class for BalsaVisitorInterface subclasses that
-// only need to override a small number of methods.
-
-#ifndef NET_TOOLS_FLIP_SERVER_NOOP_BALSA_VISITOR_H_
-#define NET_TOOLS_FLIP_SERVER_NOOP_BALSA_VISITOR_H_
-
-#include "net/tools/flip_server/balsa_visitor_interface.h"
-
-namespace net {
-
-// See file comment above.
-class NoOpBalsaVisitor : public BalsaVisitorInterface {
- public:
- NoOpBalsaVisitor() { }
- virtual ~NoOpBalsaVisitor() { }
-
- virtual void ProcessBodyInput(const char* input, size_t size) OVERRIDE { }
- virtual void ProcessBodyData(const char* input, size_t size) OVERRIDE { }
- virtual void ProcessHeaderInput(const char* input, size_t size) OVERRIDE { }
- virtual void ProcessTrailerInput(const char* input, size_t size) OVERRIDE { }
- virtual void ProcessHeaders(const BalsaHeaders& headers) OVERRIDE { }
-
- virtual void ProcessRequestFirstLine(const char* line_input,
- size_t line_length,
- const char* method_input,
- size_t method_length,
- const char* request_uri_input,
- size_t request_uri_length,
- const char* version_input,
- size_t version_length) OVERRIDE { }
- virtual void ProcessResponseFirstLine(const char* line_input,
- size_t line_length,
- const char* version_input,
- size_t version_length,
- const char* status_input,
- size_t status_length,
- const char* reason_input,
- size_t reason_length) OVERRIDE { }
- virtual void ProcessChunkLength(size_t chunk_length) OVERRIDE { }
- virtual void ProcessChunkExtensions(const char* input, size_t size) OVERRIDE {
- }
- virtual void HeaderDone() OVERRIDE { }
- virtual void MessageDone() OVERRIDE { }
- virtual void HandleHeaderError(BalsaFrame* framer) OVERRIDE { }
- virtual void HandleHeaderWarning(BalsaFrame* framer) OVERRIDE { }
- virtual void HandleChunkingError(BalsaFrame* framer) OVERRIDE { }
- virtual void HandleBodyError(BalsaFrame* framer) OVERRIDE { }
-
- private:
- DISALLOW_COPY_AND_ASSIGN(NoOpBalsaVisitor);
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_NOOP_BALSA_VISITOR_H_
diff --git a/net/tools/flip_server/output_ordering.h b/net/tools/flip_server/output_ordering.h
index 922d03f..c1441f0 100644
--- a/net/tools/flip_server/output_ordering.h
+++ b/net/tools/flip_server/output_ordering.h
@@ -11,8 +11,8 @@
#include "base/basictypes.h"
#include "base/compiler_specific.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/flip_server/constants.h"
-#include "net/tools/flip_server/epoll_server.h"
#include "net/tools/flip_server/mem_cache.h"
namespace net {
diff --git a/net/tools/flip_server/ring_buffer.h b/net/tools/flip_server/ring_buffer.h
index 03cbde7..ef660c3 100644
--- a/net/tools/flip_server/ring_buffer.h
+++ b/net/tools/flip_server/ring_buffer.h
@@ -7,7 +7,7 @@
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
-#include "net/tools/flip_server/buffer_interface.h"
+#include "net/tools/balsa/buffer_interface.h"
namespace net {
diff --git a/net/tools/flip_server/simple_buffer.cc b/net/tools/flip_server/simple_buffer.cc
deleted file mode 100644
index d94153b..0000000
--- a/net/tools/flip_server/simple_buffer.cc
+++ /dev/null
@@ -1,208 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/simple_buffer.h"
-#include "base/logging.h"
-
-// Some of the following member functions are marked inlined, even though they
-// are virtual. This may seem counter-intuitive, since virtual functions are
-// generally not eligible for inlining. Profiling results indicate that these
-// large amount of runtime is spent on virtual function dispatch on these
-// simple functions. They are virtual because of the interface this class
-// inherits from. However, it is very unlikely that anyone will sub-class
-// SimpleBuffer and change their implementation. To get rid of this baggage,
-// internal implementation (e.g., Write) explicitly use SimpleBuffer:: to
-// qualify the method calls, thus disabling the virtual dispatch and enable
-// inlining.
-
-namespace net {
-
-static const int kInitialSimpleBufferSize = 10;
-
-SimpleBuffer::SimpleBuffer()
- : storage_(new char[kInitialSimpleBufferSize]),
- write_idx_(0),
- read_idx_(0),
- storage_size_(kInitialSimpleBufferSize) {
-}
-
-SimpleBuffer::SimpleBuffer(int size)
- : write_idx_(0),
- read_idx_(0),
- storage_size_(size) {
- // Callers may try to allocate overly large blocks, but negative sizes are
- // obviously wrong.
- CHECK_GE(size, 0);
- storage_ = new char[size];
-}
-
-SimpleBuffer::~SimpleBuffer() {
- delete[] storage_;
-}
-
-
-////////////////////////////////////////////////////////////////////////////////
-
-int SimpleBuffer::ReadableBytes() const {
- return write_idx_ - read_idx_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-std::string SimpleBuffer::str() const {
- std::string s;
- char * readable_ptr;
- int readable_size;
- GetReadablePtr(&readable_ptr, &readable_size);
- s.append(readable_ptr, readable_ptr + readable_size);
- return s;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-int SimpleBuffer::BufferSize() const {
- return storage_size_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-inline int SimpleBuffer::BytesFree() const {
- return (storage_size_ - write_idx_);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-bool SimpleBuffer::Empty() const {
- return (read_idx_ == write_idx_);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-bool SimpleBuffer::Full() const {
- return ((write_idx_ == storage_size_) && (read_idx_ != write_idx_));
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// returns the number of characters written.
-// appends up-to-'size' bytes to the simplebuffer.
-int SimpleBuffer::Write(const char* bytes, int size) {
- bool has_room = ((storage_size_ - write_idx_) >= size);
- if (!has_room) {
- (void)Reserve(size);
- }
- memcpy(storage_ + write_idx_, bytes, size);
- SimpleBuffer::AdvanceWritablePtr(size);
- return size;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// stores a pointer into the simple buffer in *ptr,
-// and stores the number of characters which are allowed
-// to be written in *size.
-inline void SimpleBuffer::GetWritablePtr(char **ptr, int* size) const {
- *ptr = storage_ + write_idx_;
- *size = SimpleBuffer::BytesFree();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// stores a pointer into the simple buffer in *ptr,
-// and stores the number of characters which are allowed
-// to be read in *size.
-void SimpleBuffer::GetReadablePtr(char **ptr, int* size) const {
- *ptr = storage_ + read_idx_;
- *size = write_idx_ - read_idx_;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// returns the number of bytes read into 'bytes'
-int SimpleBuffer::Read(char* bytes, int size) {
- char * read_ptr = NULL;
- int read_size = 0;
- GetReadablePtr(&read_ptr, &read_size);
- if (read_size > size) {
- read_size = size;
- }
- memcpy(bytes, read_ptr, read_size);
- AdvanceReadablePtr(read_size);
- return read_size;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// removes all data from the simple buffer
-void SimpleBuffer::Clear() {
- read_idx_ = write_idx_ = 0;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// Attempts to reserve a contiguous block of buffer space by either reclaiming
-// old data that is already read, and reallocate large storage as needed.
-bool SimpleBuffer::Reserve(int size) {
- if (size > 0 && BytesFree() < size) {
- char * read_ptr = NULL;
- int read_size = 0;
- GetReadablePtr(&read_ptr, &read_size);
-
- if (read_size + size <= BufferSize()) {
- // Can reclaim space from already read bytes by shifting
- memmove(storage_, read_ptr, read_size);
- read_idx_ = 0;
- write_idx_ = read_size;
- CHECK_GE(BytesFree(), size);
- } else {
- // what we need is to have at least size bytes available for writing.
- // This implies that the buffer needs to be at least size bytes +
- // read_size bytes long. Since we want linear time extensions in the case
- // that we're extending this thing repeatedly, we should extend to twice
- // the current size (if that is big enough), or the size + read_size
- // bytes, whichever is larger.
- int new_storage_size = 2 * storage_size_;
- if (new_storage_size < size + read_size) {
- new_storage_size = size + read_size;
- }
-
- // have to extend the thing
- char* new_storage = new char[new_storage_size];
-
- // copy still useful info to the new buffer.
- memcpy(new_storage, read_ptr, read_size);
- // reset pointers.
- read_idx_ = 0;
- write_idx_ = read_size;
- delete[] storage_;
- storage_ = new_storage;
- storage_size_ = new_storage_size;
- }
- }
- return true;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// removes the oldest 'amount_to_consume' characters.
-void SimpleBuffer::AdvanceReadablePtr(int amount_to_advance) {
- read_idx_ += amount_to_advance;
- if (read_idx_ > storage_size_) {
- read_idx_ = storage_size_;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-// Moves the internal pointers around such that the
-// amount of data specified here is expected to
-// already be resident (as if it was Written)
-inline void SimpleBuffer::AdvanceWritablePtr(int amount_to_advance) {
- write_idx_ += amount_to_advance;
- if (write_idx_ > storage_size_) {
- write_idx_ = storage_size_;
- }
-}
-
-} // namespace net
diff --git a/net/tools/flip_server/simple_buffer.h b/net/tools/flip_server/simple_buffer.h
deleted file mode 100644
index 08f7d38..0000000
--- a/net/tools/flip_server/simple_buffer.h
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_SIMPLE_BUFFER_H__
-#define NET_TOOLS_FLIP_SERVER_SIMPLE_BUFFER_H__
-
-#include <string>
-
-#include "base/compiler_specific.h"
-#include "net/tools/flip_server/buffer_interface.h"
-
-namespace net {
-
-class SimpleBuffer : public BufferInterface {
- public:
- SimpleBuffer();
- explicit SimpleBuffer(int size);
- virtual ~SimpleBuffer();
-
- std::string str() const;
-
- typedef char * iterator;
- typedef const char * const_iterator;
-
- iterator begin() { return storage_ + read_idx_; }
- const_iterator begin() const { return storage_ + read_idx_; }
-
- iterator end() { return storage_ + write_idx_; }
- const_iterator end() const { return storage_ + write_idx_; }
-
- // The following functions all override pure virtual functions
- // in BufferInterface. See buffer_interface.h for a description
- // of what they do.
- virtual int ReadableBytes() const OVERRIDE;
- virtual int BufferSize() const OVERRIDE;
- virtual int BytesFree() const OVERRIDE;
-
- virtual bool Empty() const OVERRIDE;
- virtual bool Full() const OVERRIDE;
-
- virtual int Write(const char* bytes, int size) OVERRIDE;
-
- virtual void GetWritablePtr(char **ptr, int* size) const OVERRIDE;
-
- virtual void GetReadablePtr(char **ptr, int* size) const OVERRIDE;
-
- virtual int Read(char* bytes, int size) OVERRIDE;
-
- virtual void Clear() OVERRIDE;
-
- // This can be an expensive operation: costing a new/delete, and copying of
- // all existing data. Even if the existing buffer does not need to be
- // resized, unread data may still need to be non-destructively copied to
- // consolidate fragmented free space.
- virtual bool Reserve(int size) OVERRIDE;
-
- virtual void AdvanceReadablePtr(int amount_to_advance) OVERRIDE;
-
- virtual void AdvanceWritablePtr(int amount_to_advance) OVERRIDE;
-
- void Swap(SimpleBuffer* other) {
- char* tmp = storage_;
- storage_ = other->storage_;
- other->storage_ = tmp;
-
- int tmp_int = write_idx_;
- write_idx_ = other->write_idx_;
- other->write_idx_ = tmp_int;
-
- tmp_int = read_idx_;
- read_idx_ = other->read_idx_;
- other->read_idx_ = tmp_int;
-
- tmp_int = storage_size_;
- storage_size_ = other->storage_size_;
- other->storage_size_ = tmp_int;
- }
-
- protected:
- char* storage_;
- int write_idx_;
- int read_idx_;
- int storage_size_;
-
- private:
- //DISALLOW_COPY_AND_ASSIGN(SimpleBuffer);
-};
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_SIMPLE_BUFFER_H__
diff --git a/net/tools/flip_server/sm_connection.h b/net/tools/flip_server/sm_connection.h
index 3e21772..a79dca9 100644
--- a/net/tools/flip_server/sm_connection.h
+++ b/net/tools/flip_server/sm_connection.h
@@ -12,8 +12,8 @@
#include <string>
#include "base/compiler_specific.h"
+#include "net/tools/epoll_server/epoll_server.h"
#include "net/tools/flip_server/create_listener.h"
-#include "net/tools/flip_server/epoll_server.h"
#include "net/tools/flip_server/mem_cache.h"
#include "net/tools/flip_server/ring_buffer.h"
#include "net/tools/flip_server/sm_interface.h"
diff --git a/net/tools/flip_server/sm_interface.h b/net/tools/flip_server/sm_interface.h
index 5bc942f..28e5bc6 100644
--- a/net/tools/flip_server/sm_interface.h
+++ b/net/tools/flip_server/sm_interface.h
@@ -9,7 +9,7 @@
#include <string>
-#include "net/tools/flip_server/balsa_headers.h"
+#include "net/tools/balsa/balsa_headers.h"
namespace net {
diff --git a/net/tools/flip_server/spdy_interface.h b/net/tools/flip_server/spdy_interface.h
index 3ce1f3b..3b2e513 100644
--- a/net/tools/flip_server/spdy_interface.h
+++ b/net/tools/flip_server/spdy_interface.h
@@ -12,8 +12,8 @@
#include "base/compiler_specific.h"
#include "net/spdy/buffered_spdy_framer.h"
#include "net/spdy/spdy_protocol.h"
-#include "net/tools/flip_server/balsa_headers.h"
-#include "net/tools/flip_server/balsa_visitor_interface.h"
+#include "net/tools/balsa/balsa_headers.h"
+#include "net/tools/balsa/balsa_visitor_interface.h"
#include "net/tools/flip_server/output_ordering.h"
#include "net/tools/flip_server/sm_connection.h"
#include "net/tools/flip_server/sm_interface.h"
diff --git a/net/tools/flip_server/spdy_interface_test.cc b/net/tools/flip_server/spdy_interface_test.cc
index 7a1c6e9..4dbfea8 100644
--- a/net/tools/flip_server/spdy_interface_test.cc
+++ b/net/tools/flip_server/spdy_interface_test.cc
@@ -9,8 +9,8 @@
#include "base/memory/scoped_ptr.h"
#include "base/strings/string_piece.h"
#include "net/spdy/buffered_spdy_framer.h"
-#include "net/tools/flip_server/balsa_enums.h"
-#include "net/tools/flip_server/balsa_headers.h"
+#include "net/tools/balsa/balsa_enums.h"
+#include "net/tools/balsa/balsa_headers.h"
#include "net/tools/flip_server/flip_config.h"
#include "net/tools/flip_server/flip_test_utils.h"
#include "net/tools/flip_server/mem_cache.h"
diff --git a/net/tools/flip_server/split.cc b/net/tools/flip_server/split.cc
deleted file mode 100644
index 7900513..0000000
--- a/net/tools/flip_server/split.cc
+++ /dev/null
@@ -1,72 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "net/tools/flip_server/split.h"
-
-#include <string.h>
-
-#include <vector>
-
-#include "base/strings/string_piece.h"
-
-namespace net {
-
-// Yea, this could be done with less code duplication using
-// template magic, I know.
-void SplitStringPieceToVector(const base::StringPiece& full,
- const char* delim,
- std::vector<base::StringPiece>* vec,
- bool omit_empty_strings) {
- vec->clear();
- if (full.empty() || delim[0] == '\0')
- return;
-
- if (delim[1] == '\0') {
- base::StringPiece::const_iterator s = full.begin();
- base::StringPiece::const_iterator e = s;
- for (;e != full.end(); ++e) {
- if (*e == delim[0]) {
- if (e != s || !omit_empty_strings) {
- vec->push_back(base::StringPiece(s, e - s));
- }
- s = e;
- ++s;
- }
- }
- if (s != e) {
- --e;
- if (e != s || !omit_empty_strings) {
- vec->push_back(base::StringPiece(s, e - s));
- }
- }
- } else {
- base::StringPiece::const_iterator s = full.begin();
- base::StringPiece::const_iterator e = s;
- for (;e != full.end(); ++e) {
- bool one_matched = false;
- for (const char *d = delim; *d != '\0'; ++d) {
- if (*d == *e) {
- one_matched = true;
- break;
- }
- }
- if (one_matched) {
- if (e != s || !omit_empty_strings) {
- vec->push_back(base::StringPiece(s, e - s));
- }
- s = e;
- ++s;
- }
- }
- if (s != e) {
- --e;
- if (e != s || !omit_empty_strings) {
- vec->push_back(base::StringPiece(s, e - s));
- }
- }
- }
-}
-
-} // namespace net
-
diff --git a/net/tools/flip_server/split.h b/net/tools/flip_server/split.h
deleted file mode 100644
index aae20b0..0000000
--- a/net/tools/flip_server/split.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright (c) 2009 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_SPLIT_H_
-#define NET_TOOLS_FLIP_SERVER_SPLIT_H_
-
-#include <vector>
-#include "base/strings/string_piece.h"
-
-namespace net {
-
-// Yea, this could be done with less code duplication using
-// template magic, I know.
-void SplitStringPieceToVector(const base::StringPiece& full,
- const char* delim,
- std::vector<base::StringPiece>* vec,
- bool omit_empty_strings);
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_SPLIT_H_
-
diff --git a/net/tools/flip_server/streamer_interface.cc b/net/tools/flip_server/streamer_interface.cc
index b1612e7..8c2e0e7 100644
--- a/net/tools/flip_server/streamer_interface.cc
+++ b/net/tools/flip_server/streamer_interface.cc
@@ -6,7 +6,7 @@
#include <string>
-#include "net/tools/flip_server/balsa_frame.h"
+#include "net/tools/balsa/balsa_frame.h"
#include "net/tools/flip_server/constants.h"
#include "net/tools/flip_server/flip_config.h"
#include "net/tools/flip_server/sm_connection.h"
diff --git a/net/tools/flip_server/streamer_interface.h b/net/tools/flip_server/streamer_interface.h
index 4f09b45..efaee6b 100644
--- a/net/tools/flip_server/streamer_interface.h
+++ b/net/tools/flip_server/streamer_interface.h
@@ -8,8 +8,8 @@
#include <string>
#include "base/compiler_specific.h"
-#include "net/tools/flip_server/balsa_headers.h"
-#include "net/tools/flip_server/balsa_visitor_interface.h"
+#include "net/tools/balsa/balsa_headers.h"
+#include "net/tools/balsa/balsa_visitor_interface.h"
#include "net/tools/flip_server/sm_interface.h"
namespace net {
diff --git a/net/tools/flip_server/string_piece_utils.h b/net/tools/flip_server/string_piece_utils.h
deleted file mode 100644
index 3c46dd9..0000000
--- a/net/tools/flip_server/string_piece_utils.h
+++ /dev/null
@@ -1,83 +0,0 @@
-// Copyright (c) 2010 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef NET_TOOLS_FLIP_SERVER_STRING_PIECE_UTILS_H_
-#define NET_TOOLS_FLIP_SERVER_STRING_PIECE_UTILS_H_
-
-#include <ctype.h>
-
-#include "base/port.h"
-#include "base/strings/string_piece.h"
-
-namespace net {
-
-struct StringPieceCaseHash {
- size_t operator()(const base::StringPiece& sp) const {
- // based on __stl_string_hash in http://www.sgi.com/tech/stl/string
- size_t hash_val = 0;
- for (base::StringPiece::const_iterator it = sp.begin();
- it != sp.end(); ++it) {
- hash_val = 5 * hash_val + tolower(*it);
- }
- return hash_val;
- }
-};
-
-struct StringPieceUtils {
- static bool EqualIgnoreCase(const base::StringPiece& piece1,
- const base::StringPiece& piece2) {
- base::StringPiece::const_iterator p1i = piece1.begin();
- base::StringPiece::const_iterator p2i = piece2.begin();
- if (piece1.empty() && piece2.empty()) {
- return true;
- } else if (piece1.size() != piece2.size()) {
- return false;
- }
- while (p1i != piece1.end() && p2i != piece2.end()) {
- if (tolower(*p1i) != tolower(*p2i))
- return false;
- ++p1i;
- ++p2i;
- }
- return true;
- }
-
- static void RemoveWhitespaceContext(base::StringPiece* piece1) {
- base::StringPiece::const_iterator c = piece1->begin();
- base::StringPiece::const_iterator e = piece1->end();
- while (c != e && isspace(*c)) {
- ++c;
- }
- if (c == e) {
- *piece1 = base::StringPiece(c, e-c);
- return;
- }
- --e;
- while (c != e &&isspace(*e)) {
- --e;
- }
- ++e;
- *piece1 = base::StringPiece(c, e-c);
- }
-
- static bool StartsWithIgnoreCase(const base::StringPiece& text,
- const base::StringPiece& starts_with) {
- if (text.size() < starts_with.size())
- return false;
- return EqualIgnoreCase(text.substr(0, starts_with.size()), starts_with);
- }
-};
-struct StringPieceCaseEqual {
- bool operator()(const base::StringPiece& piece1,
- const base::StringPiece& piece2) const {
- return StringPieceUtils::EqualIgnoreCase(piece1, piece2);
- }
-};
-
-
-
-} // namespace net
-
-#endif // NET_TOOLS_FLIP_SERVER_STRING_PIECE_UTILS_H_
-