Refactor and improve CTL and other code

This commit is contained in:
Justine Tunney 2024-06-04 05:41:53 -07:00
parent 1d8f37a2f0
commit 9906f299bb
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
25 changed files with 5768 additions and 5350 deletions

View file

@ -9,4 +9,5 @@ AlignTrailingComments: false
AlignEscapedNewlines: DontAlign AlignEscapedNewlines: DontAlign
AlwaysBreakTemplateDeclarations: true AlwaysBreakTemplateDeclarations: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerAllOnOneLineOrOnePerLine: true
FixNamespaceComments: true
--- ---

File diff suppressed because it is too large Load diff

View file

@ -6,39 +6,41 @@
#include <__utility/move.h> #include <__utility/move.h>
#include <__utility/swap.h> #include <__utility/swap.h>
namespace ctl {
template<typename T> template<typename T>
class Optional class optional
{ {
public: public:
using value_type = T; using value_type = T;
~Optional() = default; ~optional() = default;
Optional() noexcept : present_(false) optional() noexcept : present_(false)
{ {
} }
Optional(const T& value) : present_(true), value_(value) optional(const T& value) : present_(true), value_(value)
{ {
} }
Optional(T&& value) : present_(true), value_(std::move(value)) optional(T&& value) : present_(true), value_(std::move(value))
{ {
} }
Optional(const Optional& other) : present_(other.present_) optional(const optional& other) : present_(other.present_)
{ {
if (present_) if (present_)
new (&value_) T(other.value_); new (&value_) T(other.value_);
} }
Optional(Optional&& other) noexcept : present_(other.present_) optional(optional&& other) noexcept : present_(other.present_)
{ {
if (present_) if (present_)
value_ = std::move(other.value_); value_ = std::move(other.value_);
} }
Optional& operator=(const Optional& other) optional& operator=(const optional& other)
{ {
if (this != &other) { if (this != &other) {
present_ = other.present_; present_ = other.present_;
@ -48,7 +50,7 @@ class Optional
return *this; return *this;
} }
Optional& operator=(Optional&& other) noexcept optional& operator=(optional&& other) noexcept
{ {
if (this != &other) { if (this != &other) {
present_ = other.present_; present_ = other.present_;
@ -104,7 +106,7 @@ class Optional
value_ = T(std::forward<Args>(args)...); value_ = T(std::forward<Args>(args)...);
} }
void swap(Optional& other) noexcept void swap(optional& other) noexcept
{ {
if (present_ && other.present_) { if (present_ && other.present_) {
std::swap(value_, other.value_); std::swap(value_, other.value_);
@ -122,4 +124,6 @@ class Optional
T value_; T value_;
}; };
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_ #endif // COSMOPOLITAN_CTL_OPTIONAL_H_

44
ctl/strcat.cc Normal file
View file

@ -0,0 +1,44 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "string.h"
#include <stdckdint.h>
#include <string.h>
namespace ctl {
string
strcat(const string_view lhs, const string_view rhs) noexcept
{
string res;
size_t need;
if (ckd_add(&need, lhs.n, rhs.n))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
res.reserve(need);
if (lhs.n)
memcpy(res.p, lhs.p, lhs.n);
if (rhs.n)
memcpy(res.p + lhs.n, rhs.p, rhs.n);
res.p[res.n = lhs.n + rhs.n] = 0;
return res;
}
} // namespace ctl

43
ctl/strcmp.cc Normal file
View file

@ -0,0 +1,43 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "string_view.h"
#include <string.h>
namespace ctl {
int
strcmp(const string_view lhs, const string_view rhs) noexcept
{
int r;
size_t m = lhs.n;
if ((m = rhs.n < m ? rhs.n : m)) {
if (!m)
return 0;
if ((r = memcmp(lhs.p, rhs.p, m)))
return r;
}
if (lhs.n == rhs.n)
return 0;
if (m < lhs.n)
return +1;
return -1;
}
} // namespace ctl

View file

@ -21,7 +21,9 @@
#include <__atomic/fence.h> #include <__atomic/fence.h>
#include <stdckdint.h> #include <stdckdint.h>
String::~String() noexcept namespace ctl {
string::~string() noexcept
{ {
if (n) { if (n) {
if (n >= c) if (n >= c)
@ -34,33 +36,33 @@ String::~String() noexcept
free(p); free(p);
} }
String::String(const char* s) noexcept string::string(const char* s) noexcept
{ {
append(s, strlen(s)); append(s, strlen(s));
} }
String::String(const String& s) noexcept string::string(const string& s) noexcept
{ {
append(s.p, s.n); append(s.p, s.n);
} }
String::String(const StringView s) noexcept string::string(const string_view s) noexcept
{ {
append(s.p, s.n); append(s.p, s.n);
} }
String::String(size_t size, char ch) noexcept string::string(size_t size, char ch) noexcept
{ {
resize(size, ch); resize(size, ch);
} }
String::String(const char* s, size_t size) noexcept string::string(const char* s, size_t size) noexcept
{ {
append(s, size); append(s, size);
} }
const char* const char*
String::c_str() const noexcept string::c_str() const noexcept
{ {
if (!n) if (!n)
return ""; return "";
@ -72,7 +74,7 @@ String::c_str() const noexcept
} }
void void
String::reserve(size_t c2) noexcept string::reserve(size_t c2) noexcept
{ {
char* p2; char* p2;
if (c2 < n) if (c2 < n)
@ -88,7 +90,7 @@ String::reserve(size_t c2) noexcept
} }
void void
String::resize(size_t n2, char ch) noexcept string::resize(size_t n2, char ch) noexcept
{ {
size_t c2; size_t c2;
if (ckd_add(&c2, n2, 1)) if (ckd_add(&c2, n2, 1))
@ -100,7 +102,7 @@ String::resize(size_t n2, char ch) noexcept
} }
void void
String::append(char ch) noexcept string::append(char ch) noexcept
{ {
if (n + 2 > c) { if (n + 2 > c) {
size_t c2 = c + 2; size_t c2 = c + 2;
@ -112,7 +114,7 @@ String::append(char ch) noexcept
} }
void void
String::grow(size_t size) noexcept string::grow(size_t size) noexcept
{ {
size_t need; size_t need;
if (ckd_add(&need, n, size)) if (ckd_add(&need, n, size))
@ -133,7 +135,7 @@ String::grow(size_t size) noexcept
} }
void void
String::append(char ch, size_t size) noexcept string::append(char ch, size_t size) noexcept
{ {
grow(size); grow(size);
if (size) if (size)
@ -142,7 +144,7 @@ String::append(char ch, size_t size) noexcept
} }
void void
String::append(const void* data, size_t size) noexcept string::append(const void* data, size_t size) noexcept
{ {
grow(size); grow(size);
if (size) if (size)
@ -151,76 +153,54 @@ String::append(const void* data, size_t size) noexcept
} }
void void
String::pop_back() noexcept string::pop_back() noexcept
{ {
if (!n) if (!n)
__builtin_trap(); __builtin_trap();
p[--n] = 0; p[--n] = 0;
} }
String& string&
String::operator=(String&& s) noexcept string::operator=(string&& s) noexcept
{ {
if (p != s.p) { if (p != s.p) {
free(p); if (p) {
p = s.p; clear();
n = s.n; append(s.p, s.n);
c = s.c; } else {
s.p = nullptr; p = s.p;
s.n = 0; n = s.n;
s.c = 0; c = s.c;
s.p = nullptr;
s.n = 0;
s.c = 0;
}
} }
return *this; return *this;
} }
static String
StrCat(const StringView lhs, const StringView rhs) noexcept
{
String res;
size_t need;
if (ckd_add(&need, lhs.n, rhs.n))
__builtin_trap();
if (ckd_add(&need, need, 1))
__builtin_trap();
res.reserve(need);
if (lhs.n)
memcpy(res.p, lhs.p, lhs.n);
if (rhs.n)
memcpy(res.p + lhs.n, rhs.p, rhs.n);
res.p[res.n = lhs.n + rhs.n] = 0;
return res;
}
String
StringView::operator+(const StringView s) const noexcept
{
return StrCat(*this, s);
}
String
String::operator+(const StringView s) const noexcept
{
return StrCat(*this, s);
}
bool bool
String::operator==(const StringView s) const noexcept string::operator==(const string_view s) const noexcept
{ {
if (n != s.n) if (n != s.n)
return false; return false;
if (!n)
return true;
return !memcmp(p, s.p, n); return !memcmp(p, s.p, n);
} }
bool bool
String::operator!=(const StringView s) const noexcept string::operator!=(const string_view s) const noexcept
{ {
if (n != s.n) if (n != s.n)
return true; return true;
if (!n)
return false;
return !!memcmp(p, s.p, n); return !!memcmp(p, s.p, n);
} }
bool bool
String::contains(const StringView s) const noexcept string::contains(const string_view s) const noexcept
{ {
if (!s.n) if (!s.n)
return true; return true;
@ -228,44 +208,27 @@ String::contains(const StringView s) const noexcept
} }
bool bool
String::ends_with(const StringView s) const noexcept string::ends_with(const string_view s) const noexcept
{ {
if (n < s.n) if (n < s.n)
return false; return false;
if (!s.n)
return true;
return !memcmp(p + n - s.n, s.p, s.n); return !memcmp(p + n - s.n, s.p, s.n);
} }
bool bool
String::starts_with(const StringView s) const noexcept string::starts_with(const string_view s) const noexcept
{ {
if (n < s.n) if (n < s.n)
return false; return false;
if (!s.n)
return true;
return !memcmp(p, s.p, s.n); return !memcmp(p, s.p, s.n);
} }
static int
StrCmp(const StringView lhs, const StringView rhs) noexcept
{
int r;
size_t m = lhs.n;
if ((m = rhs.n < m ? rhs.n : m))
if ((r = memcmp(lhs.p, rhs.p, m)))
return r;
if (lhs.n == rhs.n)
return 0;
if (m < lhs.n)
return +1;
return -1;
}
int
String::compare(const StringView s) const noexcept
{
return StrCmp(*this, s);
}
size_t size_t
String::find(char ch, size_t pos) const noexcept string::find(char ch, size_t pos) const noexcept
{ {
char* q; char* q;
if ((q = (char*)memchr(p, ch, n))) if ((q = (char*)memchr(p, ch, n)))
@ -274,7 +237,7 @@ String::find(char ch, size_t pos) const noexcept
} }
size_t size_t
String::find(const StringView s, size_t pos) const noexcept string::find(const string_view s, size_t pos) const noexcept
{ {
char* q; char* q;
if (pos > n) if (pos > n)
@ -284,8 +247,8 @@ String::find(const StringView s, size_t pos) const noexcept
return npos; return npos;
} }
String string
String::substr(size_t pos, size_t count) const noexcept string::substr(size_t pos, size_t count) const noexcept
{ {
size_t last; size_t last;
if (pos > n) if (pos > n)
@ -296,11 +259,11 @@ String::substr(size_t pos, size_t count) const noexcept
last = n; last = n;
if (last > n) if (last > n)
__builtin_trap(); __builtin_trap();
return String(p + pos, count); return string(p + pos, count);
} }
String& string&
String::replace(size_t pos, size_t count, const StringView& s) noexcept string::replace(size_t pos, size_t count, const string_view& s) noexcept
{ {
size_t last; size_t last;
if (ckd_add(&last, pos, count)) if (ckd_add(&last, pos, count))
@ -324,49 +287,8 @@ String::replace(size_t pos, size_t count, const StringView& s) noexcept
return *this; return *this;
} }
int string&
StringView::compare(const StringView s) const noexcept string::insert(size_t i, const string_view s) noexcept
{
return StrCmp(*this, s);
}
size_t
StringView::find(char ch, size_t pos) const noexcept
{
char* q;
if (n && (q = (char*)memchr(p, ch, n)))
return q - p;
return npos;
}
size_t
StringView::find(const StringView s, size_t pos) const noexcept
{
char* q;
if (pos > n)
__builtin_trap();
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
return q - p;
return npos;
}
StringView
StringView::substr(size_t pos, size_t count) const noexcept
{
size_t last;
if (pos > n)
__builtin_trap();
if (count > n - pos)
count = n - pos;
if (ckd_add(&last, pos, count))
last = n;
if (last > n)
__builtin_trap();
return StringView(p + pos, count);
}
String&
String::insert(size_t i, const StringView s) noexcept
{ {
if (i > n) if (i > n)
__builtin_trap(); __builtin_trap();
@ -384,8 +306,8 @@ String::insert(size_t i, const StringView s) noexcept
return *this; return *this;
} }
String& string&
String::erase(size_t pos, size_t count) noexcept string::erase(size_t pos, size_t count) noexcept
{ {
if (pos > n) if (pos > n)
__builtin_trap(); __builtin_trap();
@ -398,42 +320,4 @@ String::erase(size_t pos, size_t count) noexcept
return *this; return *this;
} }
bool } // namespace ctl
StringView::operator==(const StringView s) const noexcept
{
if (n == s.n)
return true;
return !memcmp(p, s.p, n);
}
bool
StringView::operator!=(const StringView s) const noexcept
{
if (n != s.n)
return true;
return !!memcmp(p, s.p, n);
}
bool
StringView::contains(const StringView s) const noexcept
{
if (!s.n)
return true;
return !!memmem(p, n, s.p, s.n);
}
bool
StringView::ends_with(const StringView s) const noexcept
{
if (n < s.n)
return false;
return !memcmp(p + n - s.n, s.p, s.n);
}
bool
StringView::starts_with(const StringView s) const noexcept
{
if (n < s.n)
return false;
return !memcmp(p, s.p, s.n);
}

View file

@ -2,111 +2,16 @@
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi // vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_STRING_H_ #ifndef COSMOPOLITAN_CTL_STRING_H_
#define COSMOPOLITAN_CTL_STRING_H_ #define COSMOPOLITAN_CTL_STRING_H_
#include "string_view.h"
struct String; namespace ctl {
struct StringView struct string;
{
const char* p;
size_t n;
static constexpr size_t npos = -1; string
strcat(const string_view, const string_view) noexcept __wur;
constexpr StringView(const char* s) noexcept struct string
: p(s), n(s ? __builtin_strlen(s) : 0)
{
}
constexpr StringView(const char* s, size_t n) noexcept : p(s), n(n)
{
}
inline constexpr ~StringView() noexcept
{
}
int compare(const StringView) const noexcept;
bool operator==(const StringView) const noexcept;
bool operator!=(const StringView) const noexcept;
bool contains(const StringView) const noexcept;
String operator+(const StringView) const noexcept;
bool ends_with(const StringView) const noexcept;
bool starts_with(const StringView) const noexcept;
StringView substr(size_t = 0, size_t = npos) const noexcept;
size_t find(char, size_t = 0) const noexcept;
size_t find(const StringView, size_t = 0) const noexcept;
constexpr StringView& operator=(const StringView& s) noexcept
{
p = s.p;
n = s.n;
return *this;
}
constexpr bool empty() const noexcept
{
return !n;
}
constexpr const char* data() const noexcept
{
return p;
}
constexpr size_t size() const noexcept
{
return n;
}
constexpr size_t length() const noexcept
{
return n;
}
constexpr const char& operator[](size_t i) const noexcept
{
if (i >= n)
__builtin_trap();
return p[i];
}
constexpr void remove_prefix(size_t count)
{
if (count > n)
__builtin_trap();
p += count;
n -= count;
}
constexpr void remove_suffix(size_t count)
{
if (count > n)
__builtin_trap();
n -= count;
}
bool operator<(const StringView& s) const noexcept
{
return compare(s) < 0;
}
bool operator<=(const StringView& s) const noexcept
{
return compare(s) <= 0;
}
bool operator>(const StringView& s) const noexcept
{
return compare(s) > 0;
}
bool operator>=(const StringView& s) const noexcept
{
return compare(s) >= 0;
}
};
struct String
{ {
char* p = nullptr; char* p = nullptr;
size_t n = 0; size_t n = 0;
@ -116,14 +21,14 @@ struct String
using const_iterator = const char*; using const_iterator = const char*;
static constexpr size_t npos = -1; static constexpr size_t npos = -1;
~String() noexcept; ~string() noexcept;
String() = default; string() = default;
String(const StringView) noexcept; string(const string_view) noexcept;
String(const char*) noexcept; string(const char*) noexcept;
String(const String&) noexcept; string(const string&) noexcept;
String(const char*, size_t) noexcept; string(const char*, size_t) noexcept;
explicit String(size_t, char = 0) noexcept; explicit string(size_t, char = 0) noexcept;
String& operator=(String&&) noexcept; string& operator=(string&&) noexcept;
const char* c_str() const noexcept; const char* c_str() const noexcept;
void pop_back() noexcept; void pop_back() noexcept;
@ -134,21 +39,19 @@ struct String
void append(char, size_t) noexcept; void append(char, size_t) noexcept;
void append(unsigned long) noexcept; void append(unsigned long) noexcept;
void append(const void*, size_t) noexcept; void append(const void*, size_t) noexcept;
String& insert(size_t, const StringView) noexcept; string& insert(size_t, const string_view) noexcept;
String& erase(size_t = 0, size_t = npos) noexcept; string& erase(size_t = 0, size_t = npos) noexcept;
String operator+(const StringView) const noexcept; string substr(size_t = 0, size_t = npos) const noexcept;
String substr(size_t = 0, size_t = npos) const noexcept; string& replace(size_t, size_t, const string_view&) noexcept;
String& replace(size_t, size_t, const StringView&) noexcept; bool operator==(const string_view) const noexcept;
bool operator==(const StringView) const noexcept; bool operator!=(const string_view) const noexcept;
bool operator!=(const StringView) const noexcept; bool contains(const string_view) const noexcept;
bool contains(const StringView) const noexcept; bool ends_with(const string_view) const noexcept;
bool ends_with(const StringView) const noexcept; bool starts_with(const string_view) const noexcept;
bool starts_with(const StringView) const noexcept;
int compare(const StringView) const noexcept;
size_t find(char, size_t = 0) const noexcept; size_t find(char, size_t = 0) const noexcept;
size_t find(const StringView, size_t = 0) const noexcept; size_t find(const string_view, size_t = 0) const noexcept;
String(String&& s) noexcept : p(s.p), n(s.n), c(s.c) string(string&& s) noexcept : p(s.p), n(s.n), c(s.c)
{ {
s.p = nullptr; s.p = nullptr;
s.n = 0; s.n = 0;
@ -252,69 +155,82 @@ struct String
append(ch); append(ch);
} }
void append(const StringView s) noexcept void append(const string_view s) noexcept
{ {
append(s.p, s.n); append(s.p, s.n);
} }
inline constexpr operator StringView() const noexcept inline constexpr operator string_view() const noexcept
{ {
return StringView(p, n); return string_view(p, n);
} }
String& operator=(const char* s) noexcept string& operator=(const char* s) noexcept
{ {
clear(); clear();
append(s); append(s);
return *this; return *this;
} }
String& operator=(const StringView s) noexcept string& operator=(const string_view s) noexcept
{ {
clear(); clear();
append(s); append(s);
return *this; return *this;
} }
String& operator+=(char x) noexcept string& operator+=(char x) noexcept
{ {
append(x); append(x);
return *this; return *this;
} }
String& operator+=(const StringView s) noexcept string& operator+=(const string_view s) noexcept
{ {
append(s); append(s);
return *this; return *this;
} }
bool operator<(const StringView s) const noexcept string operator+(const string_view s) const noexcept
{
return strcat(*this, s);
}
int compare(const string_view s) const noexcept
{
return strcmp(*this, s);
}
bool operator<(const string_view s) const noexcept
{ {
return compare(s) < 0; return compare(s) < 0;
} }
bool operator<=(const StringView s) const noexcept bool operator<=(const string_view s) const noexcept
{ {
return compare(s) <= 0; return compare(s) <= 0;
} }
bool operator>(const StringView s) const noexcept bool operator>(const string_view s) const noexcept
{ {
return compare(s) > 0; return compare(s) > 0;
} }
bool operator>=(const StringView s) const noexcept bool operator>=(const string_view s) const noexcept
{ {
return compare(s) >= 0; return compare(s) >= 0;
} }
}; };
#pragma GCC diagnostic ignored "-Wliteral-suffix" } // namespace ctl
inline String #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wliteral-suffix"
inline ctl::string
operator"" s(const char* s, size_t n) operator"" s(const char* s, size_t n)
{ {
return String(s, n); return ctl::string(s, n);
} }
#pragma GCC diagnostic pop
#endif // COSMOPOLITAN_CTL_STRING_H_ #endif // COSMOPOLITAN_CTL_STRING_H_

111
ctl/string_view.cc Normal file
View file

@ -0,0 +1,111 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "string_view.h"
#include <stdckdint.h>
#include <string.h>
#include "string.h"
namespace ctl {
size_t
string_view::find(char ch, size_t pos) const noexcept
{
char* q;
if (n && (q = (char*)memchr(p, ch, n)))
return q - p;
return npos;
}
size_t
string_view::find(const string_view s, size_t pos) const noexcept
{
char* q;
if (pos > n)
__builtin_trap();
if ((q = (char*)memmem(p + pos, n - pos, s.p, s.n)))
return q - p;
return npos;
}
string_view
string_view::substr(size_t pos, size_t count) const noexcept
{
size_t last;
if (pos > n)
__builtin_trap();
if (count > n - pos)
count = n - pos;
if (ckd_add(&last, pos, count))
last = n;
if (last > n)
__builtin_trap();
return string_view(p + pos, count);
}
bool
string_view::operator==(const string_view s) const noexcept
{
if (n != s.n)
return false;
if (!n)
return true;
return !memcmp(p, s.p, n);
}
bool
string_view::operator!=(const string_view s) const noexcept
{
if (n != s.n)
return true;
if (!n)
return false;
return !!memcmp(p, s.p, n);
}
bool
string_view::contains(const string_view s) const noexcept
{
if (!s.n)
return true;
return !!memmem(p, n, s.p, s.n);
}
bool
string_view::ends_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p + n - s.n, s.p, s.n);
}
bool
string_view::starts_with(const string_view s) const noexcept
{
if (n < s.n)
return false;
if (!s.n)
return true;
return !memcmp(p, s.p, s.n);
}
} // namespace ctl

159
ctl/string_view.h Normal file
View file

@ -0,0 +1,159 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef COSMOPOLITAN_CTL_STRINGVIEW_H_
#define COSMOPOLITAN_CTL_STRINGVIEW_H_
namespace ctl {
struct string_view;
int
strcmp(const string_view, const string_view) noexcept;
struct string_view
{
const char* p;
size_t n;
using iterator = const char*;
using const_iterator = const char*;
static constexpr size_t npos = -1;
constexpr string_view() noexcept : p(nullptr), n(0)
{
}
constexpr string_view(const char* s) noexcept
: p(s), n(s ? __builtin_strlen(s) : 0)
{
}
constexpr string_view(const char* s, size_t n) noexcept : p(s), n(n)
{
}
inline constexpr ~string_view() noexcept
{
}
bool operator==(const string_view) const noexcept;
bool operator!=(const string_view) const noexcept;
bool contains(const string_view) const noexcept;
bool ends_with(const string_view) const noexcept;
bool starts_with(const string_view) const noexcept;
string_view substr(size_t = 0, size_t = npos) const noexcept;
size_t find(char, size_t = 0) const noexcept;
size_t find(const string_view, size_t = 0) const noexcept;
constexpr string_view& operator=(const string_view& s) noexcept
{
p = s.p;
n = s.n;
return *this;
}
constexpr bool empty() const noexcept
{
return !n;
}
constexpr const char* data() const noexcept
{
return p;
}
constexpr size_t size() const noexcept
{
return n;
}
constexpr size_t length() const noexcept
{
return n;
}
constexpr const char& operator[](size_t i) const noexcept
{
if (i >= n)
__builtin_trap();
return p[i];
}
constexpr void remove_prefix(size_t count)
{
if (count > n)
__builtin_trap();
p += count;
n -= count;
}
constexpr void remove_suffix(size_t count)
{
if (count > n)
__builtin_trap();
n -= count;
}
constexpr const char& front() const
{
if (!n)
__builtin_trap();
return p[0];
}
constexpr const char& back() const
{
if (!n)
__builtin_trap();
return p[n - 1];
}
constexpr const_iterator begin() noexcept
{
return p;
}
constexpr const_iterator end() noexcept
{
return p + n;
}
constexpr const_iterator cbegin() const noexcept
{
return p;
}
constexpr const_iterator cend() const noexcept
{
return p + n;
}
int compare(const string_view s) const noexcept
{
return strcmp(*this, s);
}
bool operator<(const string_view& s) const noexcept
{
return compare(s) < 0;
}
bool operator<=(const string_view& s) const noexcept
{
return compare(s) <= 0;
}
bool operator>(const string_view& s) const noexcept
{
return compare(s) > 0;
}
bool operator>=(const string_view& s) const noexcept
{
return compare(s) >= 0;
}
};
} // namespace ctl
#endif // COSMOPOLITAN_CTL_STRINGVIEW_H_

View file

@ -6,8 +6,10 @@
#include <__utility/move.h> #include <__utility/move.h>
#include <__utility/swap.h> #include <__utility/swap.h>
namespace ctl {
template<typename T> template<typename T>
struct Vector struct vector
{ {
size_t n = 0; size_t n = 0;
size_t c = 0; size_t c = 0;
@ -16,14 +18,14 @@ struct Vector
using iterator = T*; using iterator = T*;
using const_iterator = const T*; using const_iterator = const T*;
Vector() = default; vector() = default;
~Vector() ~vector()
{ {
delete[] p; delete[] p;
} }
Vector(const Vector& other) vector(const vector& other)
{ {
n = other.n; n = other.n;
c = other.c; c = other.c;
@ -32,7 +34,7 @@ struct Vector
new (&p[i]) T(other.p[i]); new (&p[i]) T(other.p[i]);
} }
Vector(Vector&& other) noexcept vector(vector&& other) noexcept
{ {
n = other.n; n = other.n;
c = other.c; c = other.c;
@ -42,7 +44,7 @@ struct Vector
other.p = nullptr; other.p = nullptr;
} }
explicit Vector(size_t count, const T& value = T()) explicit vector(size_t count, const T& value = T())
{ {
n = count; n = count;
c = count; c = count;
@ -51,7 +53,7 @@ struct Vector
new (&p[i]) T(value); new (&p[i]) T(value);
} }
Vector& operator=(const Vector& other) vector& operator=(const vector& other)
{ {
if (this != &other) { if (this != &other) {
T* newData = new T[other.c]; T* newData = new T[other.c];
@ -66,7 +68,7 @@ struct Vector
return *this; return *this;
} }
Vector& operator=(Vector&& other) noexcept vector& operator=(vector&& other) noexcept
{ {
if (this != &other) { if (this != &other) {
delete[] p; delete[] p;
@ -231,7 +233,7 @@ struct Vector
n = n2; n = n2;
} }
void swap(Vector& other) noexcept void swap(vector& other) noexcept
{ {
std::swap(n, other.n); std::swap(n, other.n);
std::swap(c, other.c); std::swap(c, other.c);
@ -239,4 +241,6 @@ struct Vector
} }
}; };
} // namespace ctl
#endif // COSMOPOLITAN_CTL_OPTIONAL_H_ #endif // COSMOPOLITAN_CTL_OPTIONAL_H_

View file

@ -151,7 +151,7 @@ void *Worker(void *id) {
// check that client message wasn't fragmented into more reads // check that client message wasn't fragmented into more reads
InitHttpMessage(&msg, kHttpRequest); InitHttpMessage(&msg, kHttpRequest);
if ((inmsglen = ParseHttpMessage(&msg, buf, got)) <= 0) { if ((inmsglen = ParseHttpMessage(&msg, buf, got, sizeof(buf))) <= 0) {
if (!inmsglen) { if (!inmsglen) {
LOG("%6H client sent fragmented message"); LOG("%6H client sent fragmented message");
} else { } else {

View file

@ -382,8 +382,9 @@ demangle_free(struct demangle_data *h, void *ptr)
static privileged returnspointerwithnoaliases returnsnonnull void * static privileged returnspointerwithnoaliases returnsnonnull void *
demangle_malloc(struct demangle_data *h, int a, int n) demangle_malloc(struct demangle_data *h, int a, int n)
{ {
int rem;
uintptr_t ptr; uintptr_t ptr;
int rem, next, next2; index_t next, next2;
index_t *link, *link2; index_t *link, *link2;
int b = sizeof(index_t); int b = sizeof(index_t);
@ -417,10 +418,12 @@ demangle_malloc(struct demangle_data *h, int a, int n)
} }
/* Allocate new memory. */ /* Allocate new memory. */
rem = h->hoff;
h->hoff -= n; h->hoff -= n;
h->hoff &= -a; h->hoff &= -a;
h->hoff &= -b; h->hoff &= -b;
if (h->hoff > b) { if (h->hoff >= (b << 1)) {
n = rem - h->hoff;
ptr = h->heap + h->hoff; ptr = h->heap + h->hoff;
h->hoff -= b; h->hoff -= b;
((index_t *)ptr)[-1] = n; ((index_t *)ptr)[-1] = n;
@ -430,7 +433,7 @@ demangle_malloc(struct demangle_data *h, int a, int n)
} }
} }
static privileged char * static privileged returnspointerwithnoaliases char *
demangle_strdup(struct demangle_data *h, const char *s) demangle_strdup(struct demangle_data *h, const char *s)
{ {
char *d = 0; char *d = 0;
@ -728,7 +731,7 @@ demangle_vector_str_push_vector(struct demangle_data *ddata,
* If r_len is not NULL, string length will be returned. * If r_len is not NULL, string length will be returned.
* @return NULL at failed or NUL terminated new allocated string. * @return NULL at failed or NUL terminated new allocated string.
*/ */
static privileged char * static privileged returnspointerwithnoaliases char *
demangle_vector_str_substr(struct demangle_data *ddata, demangle_vector_str_substr(struct demangle_data *ddata,
const struct vector_str *v, size_t begin, size_t end, size_t *r_len) const struct vector_str *v, size_t begin, size_t end, size_t *r_len)
{ {
@ -1280,7 +1283,7 @@ hex_to_dec(char c)
* Todo * Todo
* Replace these functions to macro. * Replace these functions to macro.
*/ */
static privileged char * static privileged returnspointerwithnoaliases char *
decode_fp_to_double(struct demangle_data *ddata, const char *p, size_t len) decode_fp_to_double(struct demangle_data *ddata, const char *p, size_t len)
{ {
double f; double f;
@ -1324,7 +1327,7 @@ again:
return rtn; return rtn;
} }
static privileged char * static privileged returnspointerwithnoaliases char *
decode_fp_to_float(struct demangle_data *ddata, const char *p, size_t len) decode_fp_to_float(struct demangle_data *ddata, const char *p, size_t len)
{ {
size_t i, rtn_len, limit; size_t i, rtn_len, limit;
@ -1366,7 +1369,7 @@ again:
return rtn; return rtn;
} }
static privileged char * static privileged returnspointerwithnoaliases char *
decode_fp_to_long_double(struct demangle_data *ddata, const char *p, size_t len) decode_fp_to_long_double(struct demangle_data *ddata, const char *p, size_t len)
{ {
long double f; long double f;
@ -1410,7 +1413,7 @@ again:
return rtn; return rtn;
} }
static privileged char * static privileged returnspointerwithnoaliases char *
decode_fp_to_float128(struct demangle_data *ddata, const char *p, size_t len) decode_fp_to_float128(struct demangle_data *ddata, const char *p, size_t len)
{ {
long double f; long double f;
@ -1467,7 +1470,7 @@ decode_fp_to_float128(struct demangle_data *ddata, const char *p, size_t len)
} }
} }
static privileged char * static privileged returnspointerwithnoaliases char *
decode_fp_to_float80(struct demangle_data *ddata, const char *p, size_t len) decode_fp_to_float80(struct demangle_data *ddata, const char *p, size_t len)
{ {
long double f; long double f;

View file

@ -185,7 +185,9 @@ const char *GetHttpHeaderName(int) libcesque;
int GetHttpHeader(const char *, size_t) libcesque; int GetHttpHeader(const char *, size_t) libcesque;
void InitHttpMessage(struct HttpMessage *, int) libcesque; void InitHttpMessage(struct HttpMessage *, int) libcesque;
void DestroyHttpMessage(struct HttpMessage *) libcesque; void DestroyHttpMessage(struct HttpMessage *) libcesque;
int ParseHttpMessage(struct HttpMessage *, const char *, size_t) libcesque; void ResetHttpMessage(struct HttpMessage *, int) libcesque;
int ParseHttpMessage(struct HttpMessage *, const char *, size_t,
size_t) libcesque;
bool HeaderHas(struct HttpMessage *, const char *, int, const char *, bool HeaderHas(struct HttpMessage *, const char *, int, const char *,
size_t) libcesque; size_t) libcesque;
int64_t ParseContentLength(const char *, size_t) libcesque; int64_t ParseContentLength(const char *, size_t) libcesque;

View file

@ -16,11 +16,10 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/stdckdint.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "net/http/http.h" #include "net/http/http.h"
#define MAXIMUM (1024L * 1024L * 1024L * 1024L)
/** /**
* Parses Content-Length header. * Parses Content-Length header.
* *
@ -41,7 +40,7 @@ int64_t ParseContentLength(const char *s, size_t n) {
return -1; return -1;
r *= 10; r *= 10;
r += s[i] - '0'; r += s[i] - '0';
if (r >= MAXIMUM) if (r > 0x000000ffffffffff)
return -1; return -1;
} }
return r; return r;

View file

@ -18,7 +18,6 @@
*/ */
#include "libc/assert.h" #include "libc/assert.h"
#include "libc/limits.h" #include "libc/limits.h"
#include "libc/macros.internal.h"
#include "libc/mem/alg.h" #include "libc/mem/alg.h"
#include "libc/mem/arraylist.internal.h" #include "libc/mem/arraylist.internal.h"
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
@ -30,8 +29,6 @@
#include "libc/x/x.h" #include "libc/x/x.h"
#include "net/http/http.h" #include "net/http/http.h"
#define LIMIT (SHRT_MAX - 2)
/** /**
* Initializes HTTP message parser. * Initializes HTTP message parser.
*/ */
@ -52,6 +49,24 @@ void DestroyHttpMessage(struct HttpMessage *r) {
} }
} }
/**
* Resets http message parser state, so it can be re-used.
*
* This function amortizes the cost of malloc() in threads that process
* multiple messages in a loop.
*
* @param r is assumed to have been passed to `InitHttpMessage` earlier
*/
void ResetHttpMessage(struct HttpMessage *r, int type) {
unassert(type == kHttpRequest || type == kHttpResponse);
unsigned c = r->xheaders.c;
struct HttpHeader *p = r->xheaders.p;
bzero(r, sizeof(*r));
r->xheaders.c = c;
r->xheaders.p = p;
r->type = type;
}
/** /**
* Parses HTTP request or response. * Parses HTTP request or response.
* *
@ -81,23 +96,31 @@ void DestroyHttpMessage(struct HttpMessage *r) {
* HTTP request under MODE=rel on a Core i9 which is about three cycles * HTTP request under MODE=rel on a Core i9 which is about three cycles
* per byte or a gigabyte per second of throughput per core. * per byte or a gigabyte per second of throughput per core.
* *
* @note we assume p points to a buffer that has >=SHRT_MAX bytes * @param p needs to have at least `c` bytes available
* @param n is how many bytes have been received off the network so far
* @param c is the capacity of `p` buffer; beyond `SHRT_MAX` is ignored
* @return bytes on success, -1 on failure, 0 if more data must be read
* @note messages can't exceed 2**15 bytes
* @see HTTP/1.1 RFC2616 RFC2068 * @see HTTP/1.1 RFC2616 RFC2068
* @see HTTP/1.0 RFC1945 * @see HTTP/1.0 RFC1945
*/ */
int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) { int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n, size_t c) {
int c, h, i; int h, i, ch;
for (n = MIN(n, LIMIT); r->i < n; ++r->i) { if (n > c)
c = p[r->i] & 0xff; return einval();
n = n > SHRT_MAX ? SHRT_MAX : n;
c = c > SHRT_MAX ? SHRT_MAX : c;
for (; r->i < n; ++r->i) {
ch = p[r->i] & 255;
switch (r->t) { switch (r->t) {
case kHttpStateStart: case kHttpStateStart:
if (c == '\r' || c == '\n') if (ch == '\r' || ch == '\n')
break; // RFC7230 § 3.5 break; // RFC7230 § 3.5
if (!kHttpToken[c]) if (!kHttpToken[ch])
return ebadmsg(); return ebadmsg();
if (r->type == kHttpRequest) { if (r->type == kHttpRequest) {
r->t = kHttpStateMethod; r->t = kHttpStateMethod;
r->method = kToUpper[c]; r->method = kToUpper[ch];
r->a = 8; r->a = 8;
} else { } else {
r->t = kHttpStateVersion; r->t = kHttpStateVersion;
@ -106,52 +129,52 @@ int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
break; break;
case kHttpStateMethod: case kHttpStateMethod:
for (;;) { for (;;) {
if (c == ' ') { if (ch == ' ') {
r->a = r->i + 1; r->a = r->i + 1;
r->t = kHttpStateUri; r->t = kHttpStateUri;
break; break;
} else if (r->a == 64 || !kHttpToken[c]) { } else if (r->a == 64 || !kHttpToken[ch]) {
return ebadmsg(); return ebadmsg();
} }
c = kToUpper[c]; ch = kToUpper[ch];
r->method |= (uint64_t)c << r->a; r->method |= (uint64_t)ch << r->a;
r->a += 8; r->a += 8;
if (++r->i == n) if (++r->i == n)
break; break;
c = p[r->i] & 0xff; ch = p[r->i] & 255;
} }
break; break;
case kHttpStateUri: case kHttpStateUri:
for (;;) { for (;;) {
if (c == ' ' || c == '\r' || c == '\n') { if (ch == ' ' || ch == '\r' || ch == '\n') {
if (r->i == r->a) if (r->i == r->a)
return ebadmsg(); return ebadmsg();
r->uri.a = r->a; r->uri.a = r->a;
r->uri.b = r->i; r->uri.b = r->i;
if (c == ' ') { if (ch == ' ') {
r->a = r->i + 1; r->a = r->i + 1;
r->t = kHttpStateVersion; r->t = kHttpStateVersion;
} else { } else {
r->version = 9; r->version = 9;
r->t = c == '\r' ? kHttpStateCr : kHttpStateLf1; r->t = ch == '\r' ? kHttpStateCr : kHttpStateLf1;
} }
break; break;
} else if (c < 0x20 || (0x7F <= c && c < 0xA0)) { } else if (ch < 0x20 || (0x7F <= ch && ch < 0xA0)) {
return ebadmsg(); return ebadmsg();
} }
if (++r->i == n) if (++r->i == n)
break; break;
c = p[r->i] & 0xff; ch = p[r->i] & 255;
} }
break; break;
case kHttpStateVersion: case kHttpStateVersion:
if (c == ' ' || c == '\r' || c == '\n') { if (ch == ' ' || ch == '\r' || ch == '\n') {
if (r->i - r->a == 8 && if (r->i - r->a == 8 &&
(READ64BE(p + r->a) & 0xFFFFFFFFFF00FF00) == 0x485454502F002E00 && (READ64BE(p + r->a) & 0xFFFFFFFFFF00FF00) == 0x485454502F002E00 &&
isdigit(p[r->a + 5]) && isdigit(p[r->a + 7])) { isdigit(p[r->a + 5]) && isdigit(p[r->a + 7])) {
r->version = (p[r->a + 5] - '0') * 10 + (p[r->a + 7] - '0'); r->version = (p[r->a + 5] - '0') * 10 + (p[r->a + 7] - '0');
if (r->type == kHttpRequest) { if (r->type == kHttpRequest) {
r->t = c == '\r' ? kHttpStateCr : kHttpStateLf1; r->t = ch == '\r' ? kHttpStateCr : kHttpStateLf1;
} else { } else {
r->t = kHttpStateStatus; r->t = kHttpStateStatus;
} }
@ -162,19 +185,19 @@ int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
break; break;
case kHttpStateStatus: case kHttpStateStatus:
for (;;) { for (;;) {
if (c == ' ' || c == '\r' || c == '\n') { if (ch == ' ' || ch == '\r' || ch == '\n') {
if (r->status < 100) if (r->status < 100)
return ebadmsg(); return ebadmsg();
if (c == ' ') { if (ch == ' ') {
r->a = r->i + 1; r->a = r->i + 1;
r->t = kHttpStateMessage; r->t = kHttpStateMessage;
} else { } else {
r->t = c == '\r' ? kHttpStateCr : kHttpStateLf1; r->t = ch == '\r' ? kHttpStateCr : kHttpStateLf1;
} }
break; break;
} else if ('0' <= c && c <= '9') { } else if ('0' <= ch && ch <= '9') {
r->status *= 10; r->status *= 10;
r->status += c - '0'; r->status += ch - '0';
if (r->status > 999) if (r->status > 999)
return ebadmsg(); return ebadmsg();
} else { } else {
@ -182,36 +205,36 @@ int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
} }
if (++r->i == n) if (++r->i == n)
break; break;
c = p[r->i] & 0xff; ch = p[r->i] & 255;
} }
break; break;
case kHttpStateMessage: case kHttpStateMessage:
for (;;) { for (;;) {
if (c == '\r' || c == '\n') { if (ch == '\r' || ch == '\n') {
r->message.a = r->a; r->message.a = r->a;
r->message.b = r->i; r->message.b = r->i;
r->t = c == '\r' ? kHttpStateCr : kHttpStateLf1; r->t = ch == '\r' ? kHttpStateCr : kHttpStateLf1;
break; break;
} else if (c < 0x20 || (0x7F <= c && c < 0xA0)) { } else if (ch < 0x20 || (0x7F <= ch && ch < 0xA0)) {
return ebadmsg(); return ebadmsg();
} }
if (++r->i == n) if (++r->i == n)
break; break;
c = p[r->i] & 0xff; ch = p[r->i] & 255;
} }
break; break;
case kHttpStateCr: case kHttpStateCr:
if (c != '\n') if (ch != '\n')
return ebadmsg(); return ebadmsg();
r->t = kHttpStateLf1; r->t = kHttpStateLf1;
break; break;
case kHttpStateLf1: case kHttpStateLf1:
if (c == '\r') { if (ch == '\r') {
r->t = kHttpStateLf2; r->t = kHttpStateLf2;
break; break;
} else if (c == '\n') { } else if (ch == '\n') {
return ++r->i; return ++r->i;
} else if (!kHttpToken[c]) { } else if (!kHttpToken[ch]) {
// 1. Forbid empty header name (RFC2616 §2.2) // 1. Forbid empty header name (RFC2616 §2.2)
// 2. Forbid line folding (RFC7230 §3.2.4) // 2. Forbid line folding (RFC7230 §3.2.4)
return ebadmsg(); return ebadmsg();
@ -221,27 +244,27 @@ int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
break; break;
case kHttpStateName: case kHttpStateName:
for (;;) { for (;;) {
if (c == ':') { if (ch == ':') {
r->k.b = r->i; r->k.b = r->i;
r->t = kHttpStateColon; r->t = kHttpStateColon;
break; break;
} else if (!kHttpToken[c]) { } else if (!kHttpToken[ch]) {
return ebadmsg(); return ebadmsg();
} }
if (++r->i == n) if (++r->i == n)
break; break;
c = p[r->i] & 0xff; ch = p[r->i] & 255;
} }
break; break;
case kHttpStateColon: case kHttpStateColon:
if (c == ' ' || c == '\t') if (ch == ' ' || ch == '\t')
break; break;
r->a = r->i; r->a = r->i;
r->t = kHttpStateValue; r->t = kHttpStateValue;
// fallthrough // fallthrough
case kHttpStateValue: case kHttpStateValue:
for (;;) { for (;;) {
if (c == '\r' || c == '\n') { if (ch == '\r' || ch == '\n') {
i = r->i; i = r->i;
while (i > r->a && (p[i - 1] == ' ' || p[i - 1] == '\t')) while (i > r->a && (p[i - 1] == ' ' || p[i - 1] == '\t'))
--i; --i;
@ -273,18 +296,18 @@ int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
++r->xheaders.n; ++r->xheaders.n;
} }
} }
r->t = c == '\r' ? kHttpStateCr : kHttpStateLf1; r->t = ch == '\r' ? kHttpStateCr : kHttpStateLf1;
break; break;
} else if ((c < 0x20 && c != '\t') || (0x7F <= c && c < 0xA0)) { } else if ((ch < 0x20 && ch != '\t') || (0x7F <= ch && ch < 0xA0)) {
return ebadmsg(); return ebadmsg();
} }
if (++r->i == n) if (++r->i == n)
break; break;
c = p[r->i] & 0xff; ch = p[r->i] & 255;
} }
break; break;
case kHttpStateLf2: case kHttpStateLf2:
if (c == '\n') { if (ch == '\n') {
return ++r->i; return ++r->i;
} }
return ebadmsg(); return ebadmsg();
@ -292,9 +315,7 @@ int ParseHttpMessage(struct HttpMessage *r, const char *p, size_t n) {
__builtin_unreachable(); __builtin_unreachable();
} }
} }
if (r->i < LIMIT) { if (r->i < c)
return 0; return 0;
} else { return ebadmsg();
return ebadmsg();
}
} }

View file

@ -879,7 +879,7 @@ void *HttpWorker(void *arg) {
// parse http message // parse http message
// we're only doing one-shot parsing right now // we're only doing one-shot parsing right now
if ((inmsglen = ParseHttpMessage(msg, inbuf, got)) <= 0) { if ((inmsglen = ParseHttpMessage(msg, inbuf, got, INBUF_SIZE)) <= 0) {
++g_parsefails; ++g_parsefails;
break; break;
} }

View file

@ -1,19 +1,20 @@
// -*- mode:c++;indent-tabs-mode:nil;c-basic-offset:4;coding:utf-8 -*- // -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi // vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
// //
// Copyright 2024 Mozilla Foundation // Copyright 2024 Justine Alexandra Roberts Tunney
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Permission to use, copy, modify, and/or distribute this software for
// you may not use this file except in compliance with the License. // any purpose with or without fee is hereby granted, provided that the
// You may obtain a copy of the License at // above copyright notice and this permission notice appear in all copies.
// //
// http://www.apache.org/licenses/LICENSE-2.0 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// Unless required by applicable law or agreed to in writing, software // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// distributed under the License is distributed on an "AS IS" BASIS, // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// See the License for the specific language governing permissions and // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// limitations under the License. // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/optional.h" #include "ctl/optional.h"
@ -21,12 +22,16 @@
#include "ctl/string.h" #include "ctl/string.h"
// #include <optional>
// #include <string>
// #define ctl std
int int
main() main()
{ {
{ {
Optional<int> x; ctl::optional<int> x;
if (x) if (x)
return 1; return 1;
if (x.has_value()) if (x.has_value())
@ -34,7 +39,7 @@ main()
} }
{ {
Optional<int> x(42); ctl::optional<int> x(42);
if (!x) if (!x)
return 3; return 3;
if (!x.has_value()) if (!x.has_value())
@ -44,8 +49,8 @@ main()
} }
{ {
Optional<String> x("hello"); ctl::optional<ctl::string> x("hello");
Optional<String> y(x); ctl::optional<ctl::string> y(x);
if (!y) if (!y)
return 6; return 6;
if (!y.has_value()) if (!y.has_value())
@ -55,8 +60,8 @@ main()
} }
{ {
Optional<String> x("world"); ctl::optional<ctl::string> x("world");
Optional<String> y(std::move(x)); ctl::optional<ctl::string> y(std::move(x));
if (!y) if (!y)
return 9; return 9;
if (!y.has_value()) if (!y.has_value())
@ -66,8 +71,8 @@ main()
} }
{ {
Optional<int> x(42); ctl::optional<int> x(42);
Optional<int> y; ctl::optional<int> y;
y = x; y = x;
if (!y) if (!y)
return 13; return 13;
@ -78,8 +83,8 @@ main()
} }
{ {
Optional<String> x("hello"); ctl::optional<ctl::string> x("hello");
Optional<String> y; ctl::optional<ctl::string> y;
y = std::move(x); y = std::move(x);
if (!y) if (!y)
return 16; return 16;
@ -90,7 +95,7 @@ main()
} }
{ {
Optional<int> x(42); ctl::optional<int> x(42);
x.reset(); x.reset();
if (x) if (x)
return 20; return 20;
@ -99,7 +104,7 @@ main()
} }
{ {
Optional<String> x; ctl::optional<ctl::string> x;
x.emplace("hello"); x.emplace("hello");
if (!x) if (!x)
return 22; return 22;

View file

@ -24,14 +24,14 @@
#include "libc/str/str.h" #include "libc/str/str.h"
// #include <string> // #include <string>
// #define String std::string // #define ctl std
int int
main(int argc, char* argv[]) main()
{ {
{ {
String s; ctl::string s;
s += 'h'; s += 'h';
s += 'i'; s += 'i';
if (s != "hi") if (s != "hi")
@ -39,7 +39,7 @@ main(int argc, char* argv[])
} }
{ {
String s; ctl::string s;
if (!s.empty()) if (!s.empty())
return 6; return 6;
s.reserve(32); s.reserve(32);
@ -55,7 +55,7 @@ main(int argc, char* argv[])
} }
{ {
String s; ctl::string s;
s += "hello world how are you"; s += "hello world how are you";
s.reserve(3); s.reserve(3);
if (s != "hello world how are you") if (s != "hello world how are you")
@ -63,7 +63,7 @@ main(int argc, char* argv[])
} }
{ {
String s(4, 'x'); ctl::string s(4, 'x');
if (s != "xxxx") if (s != "xxxx")
return 12; return 12;
s.resize(3); s.resize(3);
@ -75,42 +75,42 @@ main(int argc, char* argv[])
} }
{ {
String a = "a"; ctl::string a = "a";
String b = "a"; ctl::string b = "a";
if (a.compare(b) != 0) if (a.compare(b) != 0)
return 17; return 17;
} }
{ {
String a = "a"; ctl::string a = "a";
String b = "b"; ctl::string b = "b";
if (a.compare(b) >= 0) if (a.compare(b) >= 0)
return 18; return 18;
} }
{ {
String a = "a"; ctl::string a = "a";
String b = "ab"; ctl::string b = "ab";
if (a.compare(b) >= 0) if (a.compare(b) >= 0)
return 19; return 19;
} }
{ {
String a = "ab"; ctl::string a = "ab";
String b = "a"; ctl::string b = "a";
if (a.compare(b) <= 0) if (a.compare(b) <= 0)
return 20; return 20;
} }
{ {
String a = ""; ctl::string a = "";
String b = ""; ctl::string b = "";
if (a.compare(b) != 0) if (a.compare(b) != 0)
return 21; return 21;
} }
{ {
String a = "fooBARbaz"; ctl::string a = "fooBARbaz";
if (a.substr(3, 3) != "BAR") if (a.substr(3, 3) != "BAR")
return 22; return 22;
if (a.replace(3, 3, "MOO") != "fooMOObaz") if (a.replace(3, 3, "MOO") != "fooMOObaz")
@ -118,7 +118,7 @@ main(int argc, char* argv[])
} }
{ {
String a = "fooBAR"; ctl::string a = "fooBAR";
if (a.substr(3, 3) != "BAR") if (a.substr(3, 3) != "BAR")
return 24; return 24;
if (a.replace(3, 3, "MOO") != "fooMOO") if (a.replace(3, 3, "MOO") != "fooMOO")
@ -126,7 +126,7 @@ main(int argc, char* argv[])
} }
{ {
String a = "fooBAR"; ctl::string a = "fooBAR";
if (a.substr(1, 0) != "") if (a.substr(1, 0) != "")
return 26; return 26;
if (a.replace(1, 0, "MOO") != "fMOOooBAR") if (a.replace(1, 0, "MOO") != "fMOOooBAR")
@ -142,15 +142,15 @@ main(int argc, char* argv[])
} }
{ {
String s1 = "hello"; ctl::string s1 = "hello";
String s2 = "world"; ctl::string s2 = "world";
String s3 = s1 + " " + s2; ctl::string s3 = s1 + " " + s2;
if (s3 != "hello world") if (s3 != "hello world")
return 32; return 32;
} }
{ {
String s = "hello"; ctl::string s = "hello";
if (s.size() != 5) if (s.size() != 5)
return 33; return 33;
if (s.length() != 5) if (s.length() != 5)
@ -160,7 +160,7 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
if (s[0] != 'h' || s[1] != 'e' || s[2] != 'l' || s[3] != 'l' || if (s[0] != 'h' || s[1] != 'e' || s[2] != 'l' || s[3] != 'l' ||
s[4] != 'o') s[4] != 'o')
return 36; return 36;
@ -170,17 +170,17 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
if (s.find('e') != 1) if (s.find('e') != 1)
return 38; return 38;
if (s.find('l') != 2) if (s.find('l') != 2)
return 39; return 39;
if (s.find('x') != String::npos) if (s.find('x') != ctl::string::npos)
return 40; return 40;
} }
{ {
String s = "hello"; ctl::string s = "hello";
if (!s.ends_with("lo")) if (!s.ends_with("lo"))
return 41; return 41;
if (s.ends_with("el")) if (s.ends_with("el"))
@ -188,8 +188,8 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
String sub = s.substr(1, 3); ctl::string sub = s.substr(1, 3);
if (sub != "ell") if (sub != "ell")
return 43; return 43;
sub = s.substr(2); sub = s.substr(2);
@ -198,8 +198,8 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
String s2 = s; ctl::string s2 = s;
if (s != s2) if (s != s2)
return 45; return 45;
s2[0] = 'H'; s2[0] = 'H';
@ -208,8 +208,8 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
String s2 = std::move(s); ctl::string s2 = std::move(s);
if (s2 != "hello") if (s2 != "hello")
return 47; return 47;
if (!s.empty()) if (!s.empty())
@ -217,14 +217,14 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
const char* cstr = s.c_str(); const char* cstr = s.c_str();
if (strcmp(cstr, "hello") != 0) if (strcmp(cstr, "hello") != 0)
return 49; return 49;
} }
// { // {
// String s = "hello"; // ctl::string s = "hello";
// char buffer[10]; // char buffer[10];
// s.copy(buffer, sizeof(buffer)); // s.copy(buffer, sizeof(buffer));
// if (strcmp(buffer, "hello") != 0) // if (strcmp(buffer, "hello") != 0)
@ -232,7 +232,7 @@ main(int argc, char* argv[])
// } // }
{ {
String s = "hello"; ctl::string s = "hello";
s.resize(3); s.resize(3);
if (s != "hel") if (s != "hel")
return 51; return 51;
@ -242,14 +242,14 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
s.clear(); s.clear();
if (!s.empty()) if (!s.empty())
return 53; return 53;
} }
{ {
String s = "hello"; ctl::string s = "hello";
auto it = s.begin(); auto it = s.begin();
if (*it != 'h') if (*it != 'h')
return 54; return 54;
@ -259,21 +259,21 @@ main(int argc, char* argv[])
} }
// { // {
// String s = "hello"; // ctl::string s = "hello";
// String s2 = "world"; // ctl::string s2 = "world";
// s.swap(s2); // s.swap(s2);
// if (s != "world" || s2 != "hello") // if (s != "world" || s2 != "hello")
// return 56; // return 56;
// } // }
{ {
String s = "hello"; ctl::string s = "hello";
if (s.front() != 'h' || s.back() != 'o') if (s.front() != 'h' || s.back() != 'o')
return 57; return 57;
} }
{ {
String s = "hello"; ctl::string s = "hello";
s.push_back('!'); s.push_back('!');
if (s != "hello!") if (s != "hello!")
return 58; return 58;
@ -283,42 +283,42 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
s.insert(2, "XYZ"); s.insert(2, "XYZ");
if (s != "heXYZllo") if (s != "heXYZllo")
return 60; return 60;
} }
{ {
String s = "hello"; ctl::string s = "hello";
s.erase(1, 2); s.erase(1, 2);
if (s != "hlo") if (s != "hlo")
return 61; return 61;
} }
{ {
String s = "hello"; ctl::string s = "hello";
s.replace(1, 2, "XYZ"); s.replace(1, 2, "XYZ");
if (s != "hXYZlo") if (s != "hXYZlo")
return 62; return 62;
} }
{ {
String s = "hello"; ctl::string s = "hello";
s.append(" world"); s.append(" world");
if (s != "hello world") if (s != "hello world")
return 63; return 63;
} }
// { // {
// String s = "hello"; // ctl::string s = "hello";
// s.assign("world"); // s.assign("world");
// if (s != "world") // if (s != "world")
// return 64; // return 64;
// } // }
{ {
String s = "hello"; ctl::string s = "hello";
if (s.compare("world") >= 0) if (s.compare("world") >= 0)
return 65; return 65;
if (s.compare("hello") != 0) if (s.compare("hello") != 0)
@ -328,7 +328,7 @@ main(int argc, char* argv[])
} }
{ {
String s = "hello"; ctl::string s = "hello";
if (s == "world") if (s == "world")
return 68; return 68;
if (s != "hello") if (s != "hello")
@ -339,26 +339,6 @@ main(int argc, char* argv[])
return 71; return 71;
} }
{
StringView s = "hello";
if (s.find('e') != 1)
return 72;
if (s.find('l') != 2)
return 73;
if (s.find('x') != String::npos)
return 74;
}
{
StringView s = "hello there";
s.remove_prefix(6);
if (s != "there")
return 75;
s.remove_suffix(1);
if (s != "ther")
return 76;
}
{ {
if ("hello"s != "hello") if ("hello"s != "hello")
return 77; return 77;

View file

@ -0,0 +1,180 @@
// -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
//
// Copyright 2024 Justine Alexandra Roberts Tunney
//
// Permission to use, copy, modify, and/or distribute this software for
// any purpose with or without fee is hereby granted, provided that the
// above copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/string_view.h"
#include <__utility/move.h>
#include "libc/runtime/runtime.h"
#include "libc/str/str.h"
// #include <string_view>
// #define ctl std
int
main(int argc, char* argv[])
{
{
ctl::string_view s = "hello there";
s.remove_prefix(6);
if (s != "there")
return 1;
s.remove_suffix(1);
if (s != "ther")
return 2;
}
{
ctl::string_view s = "hello";
if (s.front() != 'h' || s.back() != 'o')
return 3;
}
{
ctl::string_view s = "hello";
if (s.compare("world") >= 0)
return 4;
if (s.compare("hello") != 0)
return 5;
if (s.compare("hallo") <= 0)
return 6;
}
{
ctl::string_view s = "hello";
if (s.find('e') != 1)
return 7;
if (s.find('l') != 2)
return 8;
if (s.find('x') != ctl::string_view::npos)
return 9;
}
{
ctl::string_view s = "hello";
if (s == "world")
return 10;
if (s != "hello")
return 11;
if (s < "hallo")
return 12;
if (s > "world")
return 13;
}
{
ctl::string_view s = "hello";
auto it = s.begin();
if (*it != 'h')
return 14;
++it;
if (*it != 'e')
return 15;
}
{
ctl::string_view s = "hello";
ctl::string_view s2 = std::move(s);
if (s2 != "hello")
return 16;
if (s.empty())
return 17;
}
{
ctl::string_view s = "hello";
ctl::string_view sub = s.substr(1, 3);
if (sub != "ell")
return 18;
sub = s.substr(2);
if (sub != "llo")
return 19;
}
{
ctl::string_view s = "hello";
if (!s.ends_with("lo"))
return 20;
if (s.ends_with("el"))
return 21;
}
{
ctl::string_view s = "hello";
if (s.find('e') != 1)
return 22;
if (s.find('l') != 2)
return 23;
if (s.find('x') != ctl::string_view::npos)
return 24;
}
{
ctl::string_view s = "hello";
if (s[0] != 'h' || s[1] != 'e' || s[2] != 'l' || s[3] != 'l' ||
s[4] != 'o')
return 25;
}
{
ctl::string_view s = "hello";
if (s.size() != 5)
return 26;
if (s.length() != 5)
return 27;
}
{
ctl::string_view a = "a";
ctl::string_view b = "a";
if (a.compare(b) != 0)
return 28;
}
{
ctl::string_view a = "a";
ctl::string_view b = "b";
if (a.compare(b) >= 0)
return 29;
}
{
ctl::string_view a = "a";
ctl::string_view b = "ab";
if (a.compare(b) >= 0)
return 30;
}
{
ctl::string_view a = "ab";
ctl::string_view b = "a";
if (a.compare(b) <= 0)
return 31;
}
{
ctl::string_view a = "";
ctl::string_view b = "";
if (a.compare(b) != 0)
return 32;
}
CheckForMemoryLeaks();
return 0;
}

View file

@ -1,19 +1,20 @@
// -*- mode:c++;indent-tabs-mode:nil;c-basic-offset:4;coding:utf-8 -*- // -*- mode:c++; indent-tabs-mode:nil; c-basic-offset:4; coding:utf-8 -*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi // vi: set et ft=c++ ts=4 sts=4 sw=4 fenc=utf-8
// //
// Copyright 2024 Mozilla Foundation // Copyright 2024 Justine Alexandra Roberts Tunney
// //
// Licensed under the Apache License, Version 2.0 (the "License"); // Permission to use, copy, modify, and/or distribute this software for
// you may not use this file except in compliance with the License. // any purpose with or without fee is hereby granted, provided that the
// You may obtain a copy of the License at // above copyright notice and this permission notice appear in all copies.
// //
// http://www.apache.org/licenses/LICENSE-2.0 // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
// // WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
// Unless required by applicable law or agreed to in writing, software // WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
// distributed under the License is distributed on an "AS IS" BASIS, // AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
// See the License for the specific language governing permissions and // PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
// limitations under the License. // TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "ctl/vector.h" #include "ctl/vector.h"
@ -24,16 +25,15 @@
// #include <string> // #include <string>
// #include <vector> // #include <vector>
// #define String std::string // #define ctl std
// #define Vector std::vector
int int
main(int argc, char* argv[]) main()
{ {
{ {
int x = 3; int x = 3;
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(x); A.push_back(x);
@ -48,8 +48,8 @@ main(int argc, char* argv[])
} }
{ {
String yo = "foo"; ctl::string yo = "foo";
Vector<String> A; ctl::vector<ctl::string> A;
A.push_back("fun"); A.push_back("fun");
A.push_back(std::move(yo)); A.push_back(std::move(yo));
if (yo != "") if (yo != "")
@ -66,7 +66,7 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
if (!A.empty()) if (!A.empty())
return 11; return 11;
A.push_back(5); A.push_back(5);
@ -79,11 +79,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B(A); ctl::vector<int> B(A);
if (B.size() != 3) if (B.size() != 3)
return 15; return 15;
if (B[0] != 1 || B[1] != 2 || B[2] != 3) if (B[0] != 1 || B[1] != 2 || B[2] != 3)
@ -91,11 +91,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B(std::move(A)); ctl::vector<int> B(std::move(A));
if (A.size() != 0) if (A.size() != 0)
return 17; return 17;
if (B.size() != 3) if (B.size() != 3)
@ -105,11 +105,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B; ctl::vector<int> B;
B = A; B = A;
if (B.size() != 3) if (B.size() != 3)
return 20; return 20;
@ -118,11 +118,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B; ctl::vector<int> B;
B = std::move(A); B = std::move(A);
if (A.size() != 0) if (A.size() != 0)
return 22; return 22;
@ -133,7 +133,7 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
@ -145,7 +145,7 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.resize(5); A.resize(5);
if (A.size() != 5) if (A.size() != 5)
return 27; return 27;
@ -155,11 +155,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B; ctl::vector<int> B;
B.push_back(4); B.push_back(4);
B.push_back(5); B.push_back(5);
A.swap(B); A.swap(B);
@ -174,7 +174,7 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
@ -186,11 +186,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int>::iterator it = A.begin(); ctl::vector<int>::iterator it = A.begin();
if (*it != 1) if (*it != 1)
return 35; return 35;
++it; ++it;
@ -205,11 +205,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int>::const_iterator cit = A.cbegin(); ctl::vector<int>::const_iterator cit = A.cbegin();
if (*cit != 1) if (*cit != 1)
return 39; return 39;
++cit; ++cit;
@ -224,7 +224,7 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
A.push_back(i); A.push_back(i);
} }
@ -237,11 +237,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B(A); ctl::vector<int> B(A);
if (B.size() != 3) if (B.size() != 3)
return 53; return 53;
B.push_back(4); B.push_back(4);
@ -252,7 +252,7 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.reserve(100); A.reserve(100);
if (A.size() != 0) if (A.size() != 0)
return 56; return 56;
@ -266,11 +266,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B; ctl::vector<int> B;
B = A; B = A;
if (B.size() != 3) if (B.size() != 3)
return 60; return 60;
@ -282,11 +282,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B; ctl::vector<int> B;
B = std::move(A); B = std::move(A);
if (A.size() != 0) if (A.size() != 0)
return 63; return 63;
@ -297,11 +297,11 @@ main(int argc, char* argv[])
} }
{ {
Vector<int> A; ctl::vector<int> A;
A.push_back(1); A.push_back(1);
A.push_back(2); A.push_back(2);
A.push_back(3); A.push_back(3);
Vector<int> B; ctl::vector<int> B;
B.push_back(4); B.push_back(4);
B.push_back(5); B.push_back(5);
A.swap(B); A.swap(B);

View file

@ -62,18 +62,23 @@ TEST(ParseHttpMessage, soLittleState) {
TEST(ParseHttpMessage, testEmpty_tooShort) { TEST(ParseHttpMessage, testEmpty_tooShort) {
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(0, ParseHttpMessage(req, "", 0)); EXPECT_EQ(0, ParseHttpMessage(req, "", 0, 1));
} }
TEST(ParseHttpMessage, testTooShort) { TEST(ParseHttpMessage, testShort) {
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(0, ParseHttpMessage(req, "\r\n", 2)); EXPECT_EQ(0, ParseHttpMessage(req, "HT", 2, 32768));
}
TEST(ParseHttpMessage, testBusted) {
InitHttpMessage(req, kHttpRequest);
EXPECT_SYS(EBADMSG, -1, ParseHttpMessage(req, "\r\n", 2, 2));
} }
TEST(ParseHttpMessage, testNoHeaders) { TEST(ParseHttpMessage, testNoHeaders) {
static const char m[] = "GET /foo HTTP/1.0\r\n\r\n"; static const char m[] = "GET /foo HTTP/1.0\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("GET", method()); EXPECT_STREQ("GET", method());
EXPECT_STREQ("/foo", gc(slice(m, req->uri))); EXPECT_STREQ("/foo", gc(slice(m, req->uri)));
EXPECT_EQ(10, req->version); EXPECT_EQ(10, req->version);
@ -86,7 +91,7 @@ Host: foo.example\r\n\
Content-Length: 0\r\n\ Content-Length: 0\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("POST", method()); EXPECT_STREQ("POST", method());
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri))); EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
EXPECT_EQ(10, req->version); EXPECT_EQ(10, req->version);
@ -98,7 +103,7 @@ Content-Length: 0\r\n\
TEST(ParseHttpMessage, testHttp101) { TEST(ParseHttpMessage, testHttp101) {
static const char m[] = "GET / HTTP/1.1\r\n\r\n"; static const char m[] = "GET / HTTP/1.1\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("GET", method()); EXPECT_STREQ("GET", method());
EXPECT_STREQ("/", gc(slice(m, req->uri))); EXPECT_STREQ("/", gc(slice(m, req->uri)));
EXPECT_EQ(11, req->version); EXPECT_EQ(11, req->version);
@ -107,7 +112,7 @@ TEST(ParseHttpMessage, testHttp101) {
TEST(ParseHttpMessage, testHttp100) { TEST(ParseHttpMessage, testHttp100) {
static const char m[] = "GET / HTTP/1.0\r\n\r\n"; static const char m[] = "GET / HTTP/1.0\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("GET", method()); EXPECT_STREQ("GET", method());
EXPECT_STREQ("/", gc(slice(m, req->uri))); EXPECT_STREQ("/", gc(slice(m, req->uri)));
EXPECT_EQ(10, req->version); EXPECT_EQ(10, req->version);
@ -116,40 +121,40 @@ TEST(ParseHttpMessage, testHttp100) {
TEST(ParseHttpMessage, testUnknownMethod_canBeUsedIfYouWant) { TEST(ParseHttpMessage, testUnknownMethod_canBeUsedIfYouWant) {
static const char m[] = "#%*+_^ / HTTP/1.0\r\n\r\n"; static const char m[] = "#%*+_^ / HTTP/1.0\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("#%*+_^", method()); EXPECT_STREQ("#%*+_^", method());
} }
TEST(ParseHttpMessage, testIllegalMethod) { TEST(ParseHttpMessage, testIllegalMethod) {
static const char m[] = "ehd@oruc / HTTP/1.0\r\n\r\n"; static const char m[] = "ehd@oruc / HTTP/1.0\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m), strlen(m)));
} }
TEST(ParseHttpMessage, testIllegalMethodCasing_weUpperCaseIt) { TEST(ParseHttpMessage, testIllegalMethodCasing_weUpperCaseIt) {
static const char m[] = "get / HTTP/1.0\r\n\r\n"; static const char m[] = "get / HTTP/1.0\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("GET", method()); EXPECT_STREQ("GET", method());
} }
TEST(ParseHttpMessage, testEmptyMethod_isntAllowed) { TEST(ParseHttpMessage, testEmptyMethod_isntAllowed) {
static const char m[] = " / HTTP/1.0\r\n\r\n"; static const char m[] = " / HTTP/1.0\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m), strlen(m)));
} }
TEST(ParseHttpMessage, testEmptyUri_isntAllowed) { TEST(ParseHttpMessage, testEmptyUri_isntAllowed) {
static const char m[] = "GET HTTP/1.0\r\n\r\n"; static const char m[] = "GET HTTP/1.0\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("GET", method()); EXPECT_STREQ("GET", method());
} }
TEST(ParseHttpMessage, testHttp09) { TEST(ParseHttpMessage, testHttp09) {
static const char m[] = "GET /\r\n\r\n"; static const char m[] = "GET /\r\n\r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("GET", method()); EXPECT_STREQ("GET", method());
EXPECT_STREQ("/", gc(slice(m, req->uri))); EXPECT_STREQ("/", gc(slice(m, req->uri)));
EXPECT_EQ(9, req->version); EXPECT_EQ(9, req->version);
@ -158,7 +163,7 @@ TEST(ParseHttpMessage, testHttp09) {
TEST(ParseHttpMessage, testTinyResponse) { TEST(ParseHttpMessage, testTinyResponse) {
static const char m[] = "HTTP/1.1 429 \r\n\r\n"; static const char m[] = "HTTP/1.1 429 \r\n\r\n";
InitHttpMessage(req, kHttpResponse); InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(429, req->status); EXPECT_EQ(429, req->status);
EXPECT_STREQ("", gc(slice(m, req->message))); EXPECT_STREQ("", gc(slice(m, req->message)));
} }
@ -170,7 +175,7 @@ GET /foo?bar%20hi HTTP/1.0\r\n\
User-Agent: hi\r\n\ User-Agent: hi\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri))); EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
} }
@ -181,7 +186,7 @@ User-Agent: hi\r\n\
there\r\n\ there\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(EBADMSG, errno); EXPECT_EQ(EBADMSG, errno);
} }
@ -192,7 +197,7 @@ User-Agent: hi\r\n\
: hi\r\n\ : hi\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(EBADMSG, errno); EXPECT_EQ(EBADMSG, errno);
} }
@ -204,7 +209,7 @@ Content-Length: 0\n\
\n\ \n\
\n"; \n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m) - 1, ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m) - 1, ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("POST", method()); EXPECT_STREQ("POST", method());
EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri))); EXPECT_STREQ("/foo?bar%20hi", gc(slice(m, req->uri)));
EXPECT_EQ(10, req->version); EXPECT_EQ(10, req->version);
@ -226,7 +231,7 @@ Accept-Encoding: gzip, deflate\r\n\
Accept-Language: en-US,en;q=0.9\r\n\ Accept-Language: en-US,en;q=0.9\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("GET", method()); EXPECT_STREQ("GET", method());
EXPECT_STREQ("/tool/net/redbean.png", gc(slice(m, req->uri))); EXPECT_STREQ("/tool/net/redbean.png", gc(slice(m, req->uri)));
EXPECT_EQ(11, req->version); EXPECT_EQ(11, req->version);
@ -243,7 +248,7 @@ GET /foo?bar%20hi HTTP/1.0\r\n\
X-User-Agent: hi\r\n\ X-User-Agent: hi\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
ASSERT_EQ(1, req->xheaders.n); ASSERT_EQ(1, req->xheaders.n);
EXPECT_STREQ("X-User-Agent", gc(slice(m, req->xheaders.p[0].k))); EXPECT_STREQ("X-User-Agent", gc(slice(m, req->xheaders.p[0].k)));
EXPECT_STREQ("hi", gc(slice(m, req->xheaders.p[0].v))); EXPECT_STREQ("hi", gc(slice(m, req->xheaders.p[0].v)));
@ -256,7 +261,7 @@ Content-Type: text/html\r\n\
Content-Type: text/plain\r\n\ Content-Type: text/plain\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("text/plain", gc(slice(m, req->headers[kHttpContentType]))); EXPECT_STREQ("text/plain", gc(slice(m, req->headers[kHttpContentType])));
ASSERT_EQ(0, req->xheaders.n); ASSERT_EQ(0, req->xheaders.n);
} }
@ -271,7 +276,7 @@ Accept: text/xml\r\n\
Accept: text/css\r\n\ Accept: text/css\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("text/html", gc(slice(m, req->headers[kHttpAccept]))); EXPECT_STREQ("text/html", gc(slice(m, req->headers[kHttpAccept])));
ASSERT_EQ(4, req->xheaders.n); ASSERT_EQ(4, req->xheaders.n);
EXPECT_STREQ("Accept", gc(slice(m, req->xheaders.p[0].k))); EXPECT_STREQ("Accept", gc(slice(m, req->xheaders.p[0].k)));
@ -291,7 +296,7 @@ Accept: text/html\r\n\
Accept: text/plain\r\n\ Accept: text/plain\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("text/html", gc(slice(m, req->headers[kHttpAccept]))); EXPECT_STREQ("text/html", gc(slice(m, req->headers[kHttpAccept])));
ASSERT_EQ(1, req->xheaders.n); ASSERT_EQ(1, req->xheaders.n);
EXPECT_STREQ("Accept", gc(slice(m, req->xheaders.p[0].k))); EXPECT_STREQ("Accept", gc(slice(m, req->xheaders.p[0].k)));
@ -306,7 +311,7 @@ ACCEPT-ENCODING: gzip\r\n\
ACCEPT-encoding: bzip2\r\n\ ACCEPT-encoding: bzip2\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "gzip", -1)); EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "gzip", -1));
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "deflate", -1)); EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "deflate", -1));
EXPECT_FALSE(HeaderHas(req, m, kHttpAcceptEncoding, "funzip", -1)); EXPECT_FALSE(HeaderHas(req, m, kHttpAcceptEncoding, "funzip", -1));
@ -318,7 +323,7 @@ GET / HTTP/1.1\r\n\
: boop\r\n\ : boop\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(-1, ParseHttpMessage(req, m, strlen(m), strlen(m)));
} }
TEST(HeaderHas, testHeaderOnSameLIne) { TEST(HeaderHas, testHeaderOnSameLIne) {
@ -327,7 +332,7 @@ GET / HTTP/1.1\r\n\
Accept-Encoding: deflate, gzip, bzip2\r\n\ Accept-Encoding: deflate, gzip, bzip2\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "gzip", -1)); EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "gzip", -1));
EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "deflate", -1)); EXPECT_TRUE(HeaderHas(req, m, kHttpAcceptEncoding, "deflate", -1));
EXPECT_FALSE(HeaderHas(req, m, kHttpAcceptEncoding, "funzip", -1)); EXPECT_FALSE(HeaderHas(req, m, kHttpAcceptEncoding, "funzip", -1));
@ -339,7 +344,7 @@ OPTIONS * HTTP/1.0\r\n\
User-Agent: \t hi there \t \r\n\ User-Agent: \t hi there \t \r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_STREQ("hi there", gc(slice(m, req->headers[kHttpUserAgent]))); EXPECT_STREQ("hi there", gc(slice(m, req->headers[kHttpUserAgent])));
EXPECT_STREQ("*", gc(slice(m, req->uri))); EXPECT_STREQ("*", gc(slice(m, req->uri)));
} }
@ -349,7 +354,7 @@ TEST(ParseHttpMessage, testAbsentHost_setsSliceToZero) {
GET / HTTP/1.1\r\n\ GET / HTTP/1.1\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(0, req->headers[kHttpHost].a); EXPECT_EQ(0, req->headers[kHttpHost].a);
EXPECT_EQ(0, req->headers[kHttpHost].b); EXPECT_EQ(0, req->headers[kHttpHost].b);
} }
@ -360,7 +365,7 @@ GET / HTTP/1.1\r\n\
Host:\r\n\ Host:\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_NE(0, req->headers[kHttpHost].a); EXPECT_NE(0, req->headers[kHttpHost].a);
EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b); EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b);
} }
@ -371,25 +376,25 @@ GET / HTTP/1.1\r\n\
Host: \r\n\ Host: \r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_NE(0, req->headers[kHttpHost].a); EXPECT_NE(0, req->headers[kHttpHost].a);
EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b); EXPECT_EQ(req->headers[kHttpHost].a, req->headers[kHttpHost].b);
} }
TEST(ParseHttpResponse, testEmpty_tooShort) { TEST(ParseHttpResponse, testEmpty_tooShort) {
InitHttpMessage(req, kHttpResponse); InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(0, ParseHttpMessage(req, "", 0)); EXPECT_EQ(0, ParseHttpMessage(req, "", 0, 32768));
} }
TEST(ParseHttpResponse, testTooShort) { TEST(ParseHttpResponse, testTooShort) {
InitHttpMessage(req, kHttpResponse); InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(0, ParseHttpMessage(req, "\r\n", 2)); EXPECT_EQ(0, ParseHttpMessage(req, "HT", 2, 32768));
} }
TEST(ParseHttpResponse, testNoHeaders) { TEST(ParseHttpResponse, testNoHeaders) {
static const char m[] = "HTTP/1.0 200 OK\r\n\r\n"; static const char m[] = "HTTP/1.0 200 OK\r\n\r\n";
InitHttpMessage(req, kHttpResponse); InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(200, req->status); EXPECT_EQ(200, req->status);
EXPECT_STREQ("OK", gc(slice(m, req->message))); EXPECT_STREQ("OK", gc(slice(m, req->message)));
EXPECT_EQ(10, req->version); EXPECT_EQ(10, req->version);
@ -402,7 +407,7 @@ Host: foo.example\r\n\
Content-Length: 0\r\n\ Content-Length: 0\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpResponse); InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(200, req->status); EXPECT_EQ(200, req->status);
EXPECT_STREQ("OK", gc(slice(m, req->message))); EXPECT_STREQ("OK", gc(slice(m, req->message)));
EXPECT_EQ(10, req->version); EXPECT_EQ(10, req->version);
@ -414,7 +419,7 @@ Content-Length: 0\r\n\
TEST(ParseHttpResponse, testHttp101) { TEST(ParseHttpResponse, testHttp101) {
static const char m[] = "HTTP/1.1 300 OMG\r\n\r\n"; static const char m[] = "HTTP/1.1 300 OMG\r\n\r\n";
InitHttpMessage(req, kHttpResponse); InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(300, req->status); EXPECT_EQ(300, req->status);
EXPECT_STREQ("OMG", gc(slice(m, req->message))); EXPECT_STREQ("OMG", gc(slice(m, req->message)));
EXPECT_EQ(11, req->version); EXPECT_EQ(11, req->version);
@ -423,7 +428,7 @@ TEST(ParseHttpResponse, testHttp101) {
TEST(ParseHttpResponse, testHttp100) { TEST(ParseHttpResponse, testHttp100) {
static const char m[] = "HTTP/1.0 404 Not Found\r\n\r\n"; static const char m[] = "HTTP/1.0 404 Not Found\r\n\r\n";
InitHttpMessage(req, kHttpResponse); InitHttpMessage(req, kHttpResponse);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EXPECT_EQ(404, req->status); EXPECT_EQ(404, req->status);
EXPECT_STREQ("Not Found", gc(slice(m, req->message))); EXPECT_STREQ("Not Found", gc(slice(m, req->message)));
EXPECT_EQ(10, req->version); EXPECT_EQ(10, req->version);
@ -433,9 +438,8 @@ void DoTiniestHttpRequest(void) {
static const char m[] = "\ static const char m[] = "\
GET /\r\n\ GET /\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); ResetHttpMessage(req, kHttpRequest);
ParseHttpMessage(req, m, sizeof(m)); ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m));
DestroyHttpMessage(req);
} }
void DoTinyHttpRequest(void) { void DoTinyHttpRequest(void) {
@ -443,9 +447,8 @@ void DoTinyHttpRequest(void) {
GET /\r\n\ GET /\r\n\
Accept-Encoding: gzip\r\n\ Accept-Encoding: gzip\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); ResetHttpMessage(req, kHttpRequest);
ParseHttpMessage(req, m, sizeof(m)); ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m));
DestroyHttpMessage(req);
} }
void DoStandardChromeRequest(void) { void DoStandardChromeRequest(void) {
@ -460,9 +463,8 @@ Referer: http://10.10.10.124:8080/\r\n\
Accept-Encoding: gzip, deflate\r\n\ Accept-Encoding: gzip, deflate\r\n\
Accept-Language: en-US,en;q=0.9\r\n\ Accept-Language: en-US,en;q=0.9\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); ResetHttpMessage(req, kHttpRequest);
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m))); CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m)));
DestroyHttpMessage(req);
} }
void DoUnstandardChromeRequest(void) { void DoUnstandardChromeRequest(void) {
@ -477,18 +479,16 @@ X-Referer: http://10.10.10.124:8080/\r\n\
X-Accept-Encoding: gzip, deflate\r\n\ X-Accept-Encoding: gzip, deflate\r\n\
X-Accept-Language: en-US,en;q=0.9\r\n\ X-Accept-Language: en-US,en;q=0.9\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); ResetHttpMessage(req, kHttpRequest);
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m))); CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m)));
DestroyHttpMessage(req);
} }
void DoTiniestHttpResponse(void) { void DoTiniestHttpResponse(void) {
static const char m[] = "\ static const char m[] = "\
HTTP/1.0 200\r\n\ HTTP/1.0 200\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpResponse); ResetHttpMessage(req, kHttpResponse);
ParseHttpMessage(req, m, sizeof(m)); ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m));
DestroyHttpMessage(req);
} }
void DoTinyHttpResponse(void) { void DoTinyHttpResponse(void) {
@ -496,9 +496,8 @@ void DoTinyHttpResponse(void) {
HTTP/1.0 200\r\n\ HTTP/1.0 200\r\n\
Accept-Encoding: gzip\r\n\ Accept-Encoding: gzip\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpResponse); ResetHttpMessage(req, kHttpResponse);
ParseHttpMessage(req, m, sizeof(m)); ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m));
DestroyHttpMessage(req);
} }
void DoStandardHttpResponse(void) { void DoStandardHttpResponse(void) {
@ -518,9 +517,8 @@ Referrer-Policy: origin\r\n\
Strict-Transport-Security: max-age=31556900\r\n\ Strict-Transport-Security: max-age=31556900\r\n\
Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://cdnjs.cloudflare.com/; frame-src 'self' https://www.google.com/recaptcha/; style-src 'self' 'unsafe-inline'\r\n\ Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline' https://www.google.com/recaptcha/ https://www.gstatic.com/recaptcha/ https://cdnjs.cloudflare.com/; frame-src 'self' https://www.google.com/recaptcha/; style-src 'self' 'unsafe-inline'\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpResponse); ResetHttpMessage(req, kHttpResponse);
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m))); CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m)));
DestroyHttpMessage(req);
} }
void DoUnstandardHttpResponse(void) { void DoUnstandardHttpResponse(void) {
@ -545,12 +543,12 @@ x-slack-shared-secret-outcome: shared-secret\r\n\
via: envoy-www-iad-qd3r\r\n\ via: envoy-www-iad-qd3r\r\n\
transfer-encoding: chunked\r\n\ transfer-encoding: chunked\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpResponse); ResetHttpMessage(req, kHttpResponse);
CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m))); CHECK_EQ(sizeof(m) - 1, ParseHttpMessage(req, m, sizeof(m) - 1, sizeof(m)));
DestroyHttpMessage(req);
} }
BENCH(ParseHttpMessage, bench) { BENCH(ParseHttpMessage, bench) {
InitHttpMessage(req, kHttpRequest);
EZBENCH2("DoTiniestHttpReque", donothing, DoTiniestHttpRequest()); EZBENCH2("DoTiniestHttpReque", donothing, DoTiniestHttpRequest());
EZBENCH2("DoTinyHttpRequest", donothing, DoTinyHttpRequest()); EZBENCH2("DoTinyHttpRequest", donothing, DoTinyHttpRequest());
EZBENCH2("DoStandardChromeRe", donothing, DoStandardChromeRequest()); EZBENCH2("DoStandardChromeRe", donothing, DoStandardChromeRequest());
@ -559,6 +557,7 @@ BENCH(ParseHttpMessage, bench) {
EZBENCH2("DoTinyHttpResponse", donothing, DoTinyHttpResponse()); EZBENCH2("DoTinyHttpResponse", donothing, DoTinyHttpResponse());
EZBENCH2("DoStandardHttpResp", donothing, DoStandardHttpResponse()); EZBENCH2("DoStandardHttpResp", donothing, DoStandardHttpResponse());
EZBENCH2("DoUnstandardHttpRe", donothing, DoUnstandardHttpResponse()); EZBENCH2("DoUnstandardHttpRe", donothing, DoUnstandardHttpResponse());
DestroyHttpMessage(req);
} }
BENCH(HeaderHas, bench) { BENCH(HeaderHas, bench) {
@ -572,7 +571,7 @@ ACCEPT-ENCODING: gzip\r\n\
ACCEPT-encoding: bzip2\r\n\ ACCEPT-encoding: bzip2\r\n\
\r\n"; \r\n";
InitHttpMessage(req, kHttpRequest); InitHttpMessage(req, kHttpRequest);
EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m))); EXPECT_EQ(strlen(m), ParseHttpMessage(req, m, strlen(m), strlen(m)));
EZBENCH2("HeaderHas txt/pln", donothing, EZBENCH2("HeaderHas txt/pln", donothing,
HeaderHas(req, m, kHttpAccept, "text/plain", 7)); HeaderHas(req, m, kHttpAccept, "text/plain", 7));
EZBENCH2("HeaderHas deflate", donothing, EZBENCH2("HeaderHas deflate", donothing,

View file

@ -447,7 +447,7 @@ int _curl(int argc, char *argv[]) {
switch (t) { switch (t) {
case kHttpClientStateHeaders: case kHttpClientStateHeaders:
unassert(g); unassert(g);
if ((rc = ParseHttpMessage(&msg, p, i)) == -1) { if ((rc = ParseHttpMessage(&msg, p, i, n)) == -1) {
tinyprint(2, prog, ": ", host, " sent bad http message\n", NULL); tinyprint(2, prog, ": ", host, " sent bad http message\n", NULL);
exit(1); exit(1);
} }

View file

@ -64,7 +64,8 @@ static int LuaFetch(lua_State *L) {
return LuaNilError(L, "bad method"); return LuaNilError(L, "bad method");
} }
lua_getfield(L, 2, "followredirect"); lua_getfield(L, 2, "followredirect");
if (lua_isboolean(L, -1)) followredirect = lua_toboolean(L, -1); if (lua_isboolean(L, -1))
followredirect = lua_toboolean(L, -1);
lua_getfield(L, 2, "maxredirects"); lua_getfield(L, 2, "maxredirects");
maxredirects = luaL_optinteger(L, -1, maxredirects); maxredirects = luaL_optinteger(L, -1, maxredirects);
lua_getfield(L, 2, "numredirects"); lua_getfield(L, 2, "numredirects");
@ -162,8 +163,10 @@ static int LuaFetch(lua_State *L) {
} }
#ifndef UNSECURE #ifndef UNSECURE
if (usingssl) keepalive = kaNONE; if (usingssl)
if (usingssl && !sslinitialized) TlsInit(); keepalive = kaNONE;
if (usingssl && !sslinitialized)
TlsInit();
#endif #endif
if (url.host.n) { if (url.host.n) {
@ -189,7 +192,8 @@ static int LuaFetch(lua_State *L) {
if (!IsAcceptablePort(port, -1)) { if (!IsAcceptablePort(port, -1)) {
return LuaNilError(L, "invalid port"); return LuaNilError(L, "invalid port");
} }
if (!hosthdr) hosthdr = gc(xasprintf("%s:%s", host, port)); if (!hosthdr)
hosthdr = gc(xasprintf("%s:%s", host, port));
// check if hosthdr is in keepalive table // check if hosthdr is in keepalive table
if (keepalive && lua_istable(L, 2)) { if (keepalive && lua_istable(L, 2)) {
@ -317,7 +321,8 @@ static int LuaFetch(lua_State *L) {
if (usingssl) { if (usingssl) {
rc = mbedtls_ssl_write(&sslcli, request + i, requestlen - i); rc = mbedtls_ssl_write(&sslcli, request + i, requestlen - i);
if (rc <= 0) { if (rc <= 0) {
if (rc == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) goto VerifyFailed; if (rc == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED)
goto VerifyFailed;
close(sock); close(sock);
return LuaNilTlsError(L, "write", rc); return LuaNilTlsError(L, "write", rc);
} }
@ -373,7 +378,7 @@ static int LuaFetch(lua_State *L) {
WARNF("(ftch) HTTP client %s error", "EOF headers"); WARNF("(ftch) HTTP client %s error", "EOF headers");
goto TransportError; goto TransportError;
} }
rc = ParseHttpMessage(&msg, inbuf.p, inbuf.n); rc = ParseHttpMessage(&msg, inbuf.p, inbuf.n, inbuf.c);
if (rc == -1) { if (rc == -1) {
WARNF("(ftch) HTTP client %s error", "ParseHttpMessage"); WARNF("(ftch) HTTP client %s error", "ParseHttpMessage");
goto TransportError; goto TransportError;
@ -454,7 +459,8 @@ static int LuaFetch(lua_State *L) {
WARNF("(ftch) HTTP client %s error", "Unchunk"); WARNF("(ftch) HTTP client %s error", "Unchunk");
goto TransportError; goto TransportError;
} }
if (rc) goto Finished; if (rc)
goto Finished;
break; break;
default: default:
__builtin_unreachable(); __builtin_unreachable();
@ -462,7 +468,8 @@ static int LuaFetch(lua_State *L) {
} }
Finished: Finished:
if (paylen && logbodies) LogBody("received", inbuf.p + hdrsize, paylen); if (paylen && logbodies)
LogBody("received", inbuf.p + hdrsize, paylen);
VERBOSEF("(ftch) completed %s HTTP%02d %d %s %`'.*s", method, msg.version, VERBOSEF("(ftch) completed %s HTTP%02d %d %s %`'.*s", method, msg.version,
msg.status, urlarg, FetchHeaderLength(kHttpServer), msg.status, urlarg, FetchHeaderLength(kHttpServer),
FetchHeaderData(kHttpServer)); FetchHeaderData(kHttpServer));
@ -551,7 +558,8 @@ Finished:
DestroyHttpMessage(&msg); DestroyHttpMessage(&msg);
free(inbuf.p); free(inbuf.p);
if (!keepalive || keepalive == kaCLOSE) close(sock); if (!keepalive || keepalive == kaCLOSE)
close(sock);
return LuaFetch(L); return LuaFetch(L);
} else { } else {
lua_pushinteger(L, msg.status); lua_pushinteger(L, msg.status);
@ -559,7 +567,8 @@ Finished:
lua_pushlstring(L, inbuf.p + hdrsize, paylen); lua_pushlstring(L, inbuf.p + hdrsize, paylen);
DestroyHttpMessage(&msg); DestroyHttpMessage(&msg);
free(inbuf.p); free(inbuf.p);
if (!keepalive || keepalive == kaCLOSE) close(sock); if (!keepalive || keepalive == kaCLOSE)
close(sock);
return 3; return 3;
} }
TransportError: TransportError:

View file

@ -6458,7 +6458,7 @@ static bool HandleMessageActual(void) {
long reqtime, contime; long reqtime, contime;
char *p; char *p;
struct timespec now; struct timespec now;
if ((rc = ParseHttpMessage(&cpm.msg, inbuf.p, amtread)) != -1) { if ((rc = ParseHttpMessage(&cpm.msg, inbuf.p, amtread, inbuf.n)) != -1) {
if (!rc) if (!rc)
return false; return false;
hdrsize = rc; hdrsize = rc;

View file

@ -7,11 +7,8 @@ import sys
def GetDeps(path): def GetDeps(path):
visited = set() visited = set()
def Dive(path, inside, depth, that_isnt=None): def Dive(path, inside, depth, that_isnt=None):
sys.stdout.write('%s%s' % ('\t' * depth, path)) included = path
sys.stdout.write('\n')
if path in visited:
return
visited.add(path)
if not os.path.exists(path): if not os.path.exists(path):
if inside: if inside:
samedir = os.path.join(os.path.dirname(inside), path) samedir = os.path.join(os.path.dirname(inside), path)
@ -24,6 +21,15 @@ def GetDeps(path):
else: else:
# sys.stderr.write('not found: %s\n' % (path)) # sys.stderr.write('not found: %s\n' % (path))
return return
sys.stdout.write('\t' * depth)
sys.stdout.write(path)
sys.stdout.write('\n')
if path in visited:
return
visited.add(path)
with open(path) as f: with open(path) as f:
code = f.read() code = f.read()
for dep in re.findall(r'[.#]\s*include\s+[<"]([^">]+)[">]', code): for dep in re.findall(r'[.#]\s*include\s+[<"]([^">]+)[">]', code):