<commit_before>/*
 * libjingle
 * Copyright 2004--2005, Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Copyright 2005 Google Inc.  All Rights Reserved.
//


#ifdef WIN32
#include "talk/base/win32.h"
#else  // !WIN32
#define SEC_E_CERT_EXPIRED (-2146893016)
#endif  // !WIN32

#include "talk/base/common.h"
#include "talk/base/httpbase.h"
#include "talk/base/logging.h"
#include "talk/base/socket.h"
#include "talk/base/stringutils.h"
#include "talk/base/thread.h"

namespace talk_base {

//////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////

bool MatchHeader(const char* str, size_t len, HttpHeader header) {
  const char* const header_str = ToString(header);
  const size_t header_len = strlen(header_str);
  return (len == header_len) && (_strnicmp(str, header_str, header_len) == 0);
}

enum {
  MSG_READ
};

//////////////////////////////////////////////////////////////////////
// HttpParser
//////////////////////////////////////////////////////////////////////

HttpParser::HttpParser() {
  reset();
}

HttpParser::~HttpParser() {
}

void
HttpParser::reset() {
  state_ = ST_LEADER;
  chunked_ = false;
  data_size_ = SIZE_UNKNOWN;
}

HttpParser::ProcessResult
HttpParser::Process(const char* buffer, size_t len, size_t* processed,
                    HttpError* error) {
  *processed = 0;
  *error = HE_NONE;

  if (state_ >= ST_COMPLETE) {
    ASSERT(false);
    return PR_COMPLETE;
  }

  while (true) {
    if (state_ < ST_DATA) {
      size_t pos = *processed;
      while ((pos < len) && (buffer[pos] != '\n')) {
        pos += 1;
      }
      if (pos >= len) {
        break;  // don't have a full header
      }
      const char* line = buffer + *processed;
      size_t len = (pos - *processed);
      *processed = pos + 1;
      while ((len > 0) && isspace(static_cast<unsigned char>(line[len-1]))) {
        len -= 1;
      }
      ProcessResult result = ProcessLine(line, len, error);
      LOG(LS_VERBOSE) << "Processed line, result=" << result;

      if (PR_CONTINUE != result) {
        return result;
      }
    } else if (data_size_ == 0) {
      if (chunked_) {
        state_ = ST_CHUNKTERM;
      } else {
        return PR_COMPLETE;
      }
    } else {
      size_t available = len - *processed;
      if (available <= 0) {
        break; // no more data
      }
      if ((data_size_ != SIZE_UNKNOWN) && (available > data_size_)) {
        available = data_size_;
      }
      size_t read = 0;
      ProcessResult result = ProcessData(buffer + *processed, available, read,
                                         error);
      LOG(LS_VERBOSE) << "Processed data, result: " << result << " read: "
                      << read << " err: " << error;

      if (PR_CONTINUE != result) {
        return result;
      }
      *processed += read;
      if (data_size_ != SIZE_UNKNOWN) {
        data_size_ -= read;
      }
    }
  }

  return PR_CONTINUE;
}

HttpParser::ProcessResult
HttpParser::ProcessLine(const char* line, size_t len, HttpError* error) {
  LOG_F(LS_VERBOSE) << " state: " << state_ << " line: "
                    << std::string(line, len) << " len: " << len << " err: "
                    << error;

  switch (state_) {
  case ST_LEADER:
    state_ = ST_HEADERS;
    return ProcessLeader(line, len, error);

  case ST_HEADERS:
    if (len > 0) {
      const char* value = strchrn(line, len, ':');
      if (!value) {
        *error = HE_PROTOCOL;
        return PR_COMPLETE;
      }
      size_t nlen = (value - line);
      const char* eol = line + len;
      do {
        value += 1;
      } while ((value < eol) && isspace(static_cast<unsigned char>(*value)));
      size_t vlen = eol - value;
      if (MatchHeader(line, nlen, HH_CONTENT_LENGTH)) {
	unsigned int temp_size;
        if (sscanf(value, "%u", &temp_size) != 1) {
          *error = HE_PROTOCOL;
          return PR_COMPLETE;
        }
	data_size_ = static_cast<size_t>(temp_size);
      } else if (MatchHeader(line, nlen, HH_TRANSFER_ENCODING)) {
        if ((vlen == 7) && (_strnicmp(value, "chunked", 7) == 0)) {<commit_msg>sscanf isn't safe with strings that aren't null-terminated. In such case, create a local copy that is null-terminated first.<commit_after>/*
 * libjingle
 * Copyright 2004--2005, Google Inc.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *  1. Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *  2. Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *  3. The name of the author may not be used to endorse or promote products
 *     derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

// Copyright 2005 Google Inc.  All Rights Reserved.
//


#ifdef WIN32
#include "talk/base/win32.h"
#else  // !WIN32
#define SEC_E_CERT_EXPIRED (-2146893016)
#endif  // !WIN32

#include "talk/base/common.h"
#include "talk/base/httpbase.h"
#include "talk/base/logging.h"
#include "talk/base/socket.h"
#include "talk/base/stringutils.h"
#include "talk/base/thread.h"

namespace talk_base {

//////////////////////////////////////////////////////////////////////
// Helpers
//////////////////////////////////////////////////////////////////////

bool MatchHeader(const char* str, size_t len, HttpHeader header) {
  const char* const header_str = ToString(header);
  const size_t header_len = strlen(header_str);
  return (len == header_len) && (_strnicmp(str, header_str, header_len) == 0);
}

enum {
  MSG_READ
};

//////////////////////////////////////////////////////////////////////
// HttpParser
//////////////////////////////////////////////////////////////////////

HttpParser::HttpParser() {
  reset();
}

HttpParser::~HttpParser() {
}

void
HttpParser::reset() {
  state_ = ST_LEADER;
  chunked_ = false;
  data_size_ = SIZE_UNKNOWN;
}

HttpParser::ProcessResult
HttpParser::Process(const char* buffer, size_t len, size_t* processed,
                    HttpError* error) {
  *processed = 0;
  *error = HE_NONE;

  if (state_ >= ST_COMPLETE) {
    ASSERT(false);
    return PR_COMPLETE;
  }

  while (true) {
    if (state_ < ST_DATA) {
      size_t pos = *processed;
      while ((pos < len) && (buffer[pos] != '\n')) {
        pos += 1;
      }
      if (pos >= len) {
        break;  // don't have a full header
      }
      const char* line = buffer + *processed;
      size_t len = (pos - *processed);
      *processed = pos + 1;
      while ((len > 0) && isspace(static_cast<unsigned char>(line[len-1]))) {
        len -= 1;
      }
      ProcessResult result = ProcessLine(line, len, error);
      LOG(LS_VERBOSE) << "Processed line, result=" << result;

      if (PR_CONTINUE != result) {
        return result;
      }
    } else if (data_size_ == 0) {
      if (chunked_) {
        state_ = ST_CHUNKTERM;
      } else {
        return PR_COMPLETE;
      }
    } else {
      size_t available = len - *processed;
      if (available <= 0) {
        break; // no more data
      }
      if ((data_size_ != SIZE_UNKNOWN) && (available > data_size_)) {
        available = data_size_;
      }
      size_t read = 0;
      ProcessResult result = ProcessData(buffer + *processed, available, read,
                                         error);
      LOG(LS_VERBOSE) << "Processed data, result: " << result << " read: "
                      << read << " err: " << error;

      if (PR_CONTINUE != result) {
        return result;
      }
      *processed += read;
      if (data_size_ != SIZE_UNKNOWN) {
        data_size_ -= read;
      }
    }
  }

  return PR_CONTINUE;
}

HttpParser::ProcessResult
HttpParser::ProcessLine(const char* line, size_t len, HttpError* error) {
  LOG_F(LS_VERBOSE) << " state: " << state_ << " line: "
                    << std::string(line, len) << " len: " << len << " err: "
                    << error;

  switch (state_) {
  case ST_LEADER:
    state_ = ST_HEADERS;
    return ProcessLeader(line, len, error);

  case ST_HEADERS:
    if (len > 0) {
      const char* value = strchrn(line, len, ':');
      if (!value) {
        *error = HE_PROTOCOL;
        return PR_COMPLETE;
      }
      size_t nlen = (value - line);
      const char* eol = line + len;
      do {
        value += 1;
      } while ((value < eol) && isspace(static_cast<unsigned char>(*value)));
      size_t vlen = eol - value;
      if (MatchHeader(line, nlen, HH_CONTENT_LENGTH)) {
        // sscanf isn't safe with strings that aren't null-terminated, and there
        // is no guarantee that |value| is.
        // Create a local copy that is null-terminated.
        std::string value_str(value, vlen);
        unsigned int temp_size;
        if (sscanf(value_str.c_str(), "%u", &temp_size) != 1) {
          *error = HE_PROTOCOL;
          return PR_COMPLETE;
        }
        data_size_ = static_cast<size_t>(temp_size);
      } else if (MatchHeader(line, nlen, HH_TRANSFER_ENCODING)) {
        if ((vlen == 7) && (_strnicmp(value, "chunked", 7) == 0)) {
{'fraction_non_alphanumeric': 0.15878437554738134, 'fraction_numerical': 0.008582939218777369, 'mean_word_length': 2.2542034767740096, 'pattern_counts': {'":': 0, '<': 81, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1406369', 'n_tokens_mistral': 3538, 'n_tokens_neox': 3341, 'n_words': 1076}