2012-01-29 16:34:10 +01:00
|
|
|
|
/*
|
2014-03-30 12:09:21 +02:00
|
|
|
|
* nghttp2 - HTTP/2 C Library
|
2012-01-29 16:34:10 +01:00
|
|
|
|
*
|
|
|
|
|
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
|
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
|
|
|
* a copy of this software and associated documentation files (the
|
|
|
|
|
* "Software"), to deal in the Software without restriction, including
|
|
|
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
|
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
|
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
|
|
|
* the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice shall be
|
|
|
|
|
* included in all copies or substantial portions of the Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
|
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
|
|
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
|
|
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
|
|
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
*/
|
|
|
|
|
#include "util.h"
|
|
|
|
|
|
2012-02-07 17:50:58 +01:00
|
|
|
|
#include <time.h>
|
2014-03-15 07:32:38 +01:00
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <netdb.h>
|
2014-07-05 11:22:40 +02:00
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <fcntl.h>
|
2012-02-07 17:50:58 +01:00
|
|
|
|
|
2013-08-10 17:08:44 +02:00
|
|
|
|
#include <cassert>
|
2012-01-29 16:34:10 +01:00
|
|
|
|
#include <cstdio>
|
2012-02-07 17:50:58 +01:00
|
|
|
|
#include <cstring>
|
2014-01-08 17:27:56 +01:00
|
|
|
|
#include <iostream>
|
2012-01-29 16:34:10 +01:00
|
|
|
|
|
2013-03-07 13:17:55 +01:00
|
|
|
|
#include "timegm.h"
|
|
|
|
|
|
2013-07-12 17:19:03 +02:00
|
|
|
|
namespace nghttp2 {
|
2012-01-29 16:34:10 +01:00
|
|
|
|
|
|
|
|
|
namespace util {
|
|
|
|
|
|
2012-11-23 13:14:39 +01:00
|
|
|
|
const char DEFAULT_STRIP_CHARSET[] = "\r\n\t ";
|
2012-01-29 16:34:10 +01:00
|
|
|
|
|
2014-05-14 15:39:28 +02:00
|
|
|
|
const char UPPER_XDIGITS[] = "0123456789ABCDEF";
|
|
|
|
|
|
2012-01-29 16:34:10 +01:00
|
|
|
|
bool isAlpha(const char c)
|
|
|
|
|
{
|
|
|
|
|
return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isDigit(const char c)
|
|
|
|
|
{
|
|
|
|
|
return '0' <= c && c <= '9';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isHexDigit(const char c)
|
|
|
|
|
{
|
|
|
|
|
return isDigit(c) || ('A' <= c && c <= 'F') || ('a' <= c && c <= 'f');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool inRFC3986UnreservedChars(const char c)
|
|
|
|
|
{
|
|
|
|
|
static const char unreserved[] = { '-', '.', '_', '~' };
|
|
|
|
|
return isAlpha(c) || isDigit(c) ||
|
|
|
|
|
std::find(&unreserved[0], &unreserved[4], c) != &unreserved[4];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string percentEncode(const unsigned char* target, size_t len)
|
|
|
|
|
{
|
|
|
|
|
std::string dest;
|
|
|
|
|
for(size_t i = 0; i < len; ++i) {
|
2014-05-14 15:39:28 +02:00
|
|
|
|
unsigned char c = target[i];
|
|
|
|
|
|
|
|
|
|
if(inRFC3986UnreservedChars(c)) {
|
|
|
|
|
dest += c;
|
2012-01-29 16:34:10 +01:00
|
|
|
|
} else {
|
2014-05-14 15:39:28 +02:00
|
|
|
|
dest += "%";
|
|
|
|
|
dest += UPPER_XDIGITS[c >> 4];
|
|
|
|
|
dest += UPPER_XDIGITS[(c & 0x0f)];
|
2012-01-29 16:34:10 +01:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string percentEncode(const std::string& target)
|
|
|
|
|
{
|
|
|
|
|
return percentEncode(reinterpret_cast<const unsigned char*>(target.c_str()),
|
|
|
|
|
target.size());
|
|
|
|
|
}
|
|
|
|
|
|
2014-04-03 06:20:50 +02:00
|
|
|
|
bool in_token(char c)
|
|
|
|
|
{
|
|
|
|
|
static const char extra[] = {
|
|
|
|
|
'!', '#', '$', '%', '&', '\'', '*', '+', '-', '.', '^', '_', '`', '|', '~'
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
return isAlpha(c) || isDigit(c) ||
|
|
|
|
|
std::find(&extra[0], &extra[sizeof(extra)], c) != &extra[sizeof(extra)];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string percent_encode_token(const std::string& target)
|
|
|
|
|
{
|
|
|
|
|
auto len = target.size();
|
|
|
|
|
std::string dest;
|
|
|
|
|
|
|
|
|
|
for(size_t i = 0; i < len; ++i) {
|
2014-05-14 15:39:28 +02:00
|
|
|
|
unsigned char c = target[i];
|
|
|
|
|
|
2014-04-03 06:20:50 +02:00
|
|
|
|
if(c != '%' && in_token(c)) {
|
|
|
|
|
dest += c;
|
|
|
|
|
} else {
|
2014-05-14 15:39:28 +02:00
|
|
|
|
dest += "%";
|
|
|
|
|
dest += UPPER_XDIGITS[c >> 4];
|
|
|
|
|
dest += UPPER_XDIGITS[(c & 0x0f)];
|
2014-04-03 06:20:50 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dest;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-29 16:34:10 +01:00
|
|
|
|
std::string percentDecode
|
|
|
|
|
(std::string::const_iterator first, std::string::const_iterator last)
|
|
|
|
|
{
|
|
|
|
|
std::string result;
|
|
|
|
|
for(; first != last; ++first) {
|
|
|
|
|
if(*first == '%') {
|
|
|
|
|
if(first+1 != last && first+2 != last &&
|
|
|
|
|
isHexDigit(*(first+1)) && isHexDigit(*(first+2))) {
|
|
|
|
|
std::string numstr(first+1, first+3);
|
|
|
|
|
result += strtol(numstr.c_str(), 0, 16);
|
|
|
|
|
first += 2;
|
|
|
|
|
} else {
|
|
|
|
|
result += *first;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result += *first;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-07 17:50:58 +01:00
|
|
|
|
std::string http_date(time_t t)
|
|
|
|
|
{
|
|
|
|
|
char buf[32];
|
2014-05-14 14:23:21 +02:00
|
|
|
|
tm tms;
|
|
|
|
|
|
|
|
|
|
if(gmtime_r(&t, &tms) == nullptr) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto rv = strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S GMT", &tms);
|
|
|
|
|
return std::string(&buf[0], &buf[rv]);
|
2012-02-07 17:50:58 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
time_t parse_http_date(const std::string& s)
|
|
|
|
|
{
|
|
|
|
|
tm tm;
|
|
|
|
|
memset(&tm, 0, sizeof(tm));
|
|
|
|
|
char* r = strptime(s.c_str(), "%a, %d %b %Y %H:%M:%S GMT", &tm);
|
|
|
|
|
if(r == 0) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return timegm(&tm);
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-19 10:05:12 +02:00
|
|
|
|
bool startsWith(const std::string& a, const std::string& b)
|
|
|
|
|
{
|
|
|
|
|
return startsWith(a.begin(), a.end(), b.begin(), b.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool istartsWith(const std::string& a, const std::string& b)
|
|
|
|
|
{
|
|
|
|
|
return istartsWith(a.begin(), a.end(), b.begin(), b.end());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
void streq_advance(const char **ap, const char **bp)
|
|
|
|
|
{
|
|
|
|
|
for(; **ap && **bp && lowcase(**ap) == lowcase(**bp); ++*ap, ++*bp);
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
bool istartsWith(const char *a, const char* b)
|
|
|
|
|
{
|
|
|
|
|
if(!a || !b) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
streq_advance(&a, &b);
|
|
|
|
|
return !*b;
|
|
|
|
|
}
|
|
|
|
|
|
2012-02-07 17:50:58 +01:00
|
|
|
|
bool endsWith(const std::string& a, const std::string& b)
|
|
|
|
|
{
|
|
|
|
|
return endsWith(a.begin(), a.end(), b.begin(), b.end());
|
|
|
|
|
}
|
2013-12-06 16:32:14 +01:00
|
|
|
|
|
2014-01-16 15:41:13 +01:00
|
|
|
|
bool strieq(const std::string& a, const std::string& b)
|
|
|
|
|
{
|
|
|
|
|
if(a.size() != b.size()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for(size_t i = 0; i < a.size(); ++i) {
|
|
|
|
|
if(lowcase(a[i]) != lowcase(b[i])) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2012-05-19 10:05:12 +02:00
|
|
|
|
bool strieq(const char *a, const char *b)
|
|
|
|
|
{
|
|
|
|
|
if(!a || !b) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for(; *a && *b && lowcase(*a) == lowcase(*b); ++a, ++b);
|
|
|
|
|
return !*a && !*b;
|
|
|
|
|
}
|
2012-02-07 17:50:58 +01:00
|
|
|
|
|
2013-07-19 17:08:14 +02:00
|
|
|
|
bool strieq(const char *a, const uint8_t *b, size_t bn)
|
|
|
|
|
{
|
|
|
|
|
if(!a || !b) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2013-07-21 16:49:12 +02:00
|
|
|
|
const uint8_t *blast = b + bn;
|
2013-08-10 17:08:44 +02:00
|
|
|
|
for(; *a && b != blast && lowcase(*a) == lowcase(*b); ++a, ++b);
|
2013-07-21 16:49:12 +02:00
|
|
|
|
return !*a && b == blast;
|
2013-07-19 17:08:14 +02:00
|
|
|
|
}
|
|
|
|
|
|
2013-08-10 17:08:44 +02:00
|
|
|
|
int strcompare(const char *a, const uint8_t *b, size_t bn)
|
|
|
|
|
{
|
|
|
|
|
assert(a && b);
|
|
|
|
|
const uint8_t *blast = b + bn;
|
|
|
|
|
for(; *a && b != blast; ++a, ++b) {
|
|
|
|
|
if(*a < *b) {
|
|
|
|
|
return -1;
|
|
|
|
|
} else if(*a > *b) {
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(!*a && b == blast) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else if(b == blast) {
|
|
|
|
|
return 1;
|
|
|
|
|
} else {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-04 16:48:31 +02:00
|
|
|
|
bool strifind(const char *a, const char *b)
|
|
|
|
|
{
|
|
|
|
|
if(!a || !b) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for(size_t i = 0; a[i]; ++i) {
|
|
|
|
|
const char *ap = &a[i], *bp = b;
|
|
|
|
|
for(; *ap && *bp && lowcase(*ap) == lowcase(*bp); ++ap, ++bp);
|
|
|
|
|
if(!*bp) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2012-11-18 13:23:13 +01:00
|
|
|
|
char upcase(char c)
|
|
|
|
|
{
|
|
|
|
|
if('a' <= c && c <= 'z') {
|
|
|
|
|
return c-'a'+'A';
|
|
|
|
|
} else {
|
|
|
|
|
return c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-14 16:09:33 +02:00
|
|
|
|
namespace {
|
|
|
|
|
const char LOWER_XDIGITS[] = "0123456789abcdef";
|
|
|
|
|
} // namespace
|
|
|
|
|
|
2013-07-15 17:15:04 +02:00
|
|
|
|
std::string format_hex(const unsigned char *s, size_t len)
|
|
|
|
|
{
|
|
|
|
|
std::string res;
|
2014-05-14 16:09:33 +02:00
|
|
|
|
res.resize(len * 2);
|
|
|
|
|
|
2013-07-15 17:15:04 +02:00
|
|
|
|
for(size_t i = 0; i < len; ++i) {
|
2014-05-14 16:09:33 +02:00
|
|
|
|
unsigned char c = s[i];
|
|
|
|
|
|
|
|
|
|
res[i * 2] = LOWER_XDIGITS[c >> 4];
|
|
|
|
|
res[i * 2 + 1] = LOWER_XDIGITS[c & 0x0f];
|
2013-07-15 17:15:04 +02:00
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-03 11:51:01 +02:00
|
|
|
|
void to_token68(std::string& base64str)
|
|
|
|
|
{
|
|
|
|
|
for(auto i = std::begin(base64str); i != std::end(base64str); ++i) {
|
|
|
|
|
switch(*i) {
|
|
|
|
|
case '+':
|
|
|
|
|
*i = '-';
|
|
|
|
|
break;
|
|
|
|
|
case '/':
|
|
|
|
|
*i = '_';
|
|
|
|
|
break;
|
|
|
|
|
case '=':
|
|
|
|
|
base64str.erase(i, std::end(base64str));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void to_base64(std::string& token68str)
|
|
|
|
|
{
|
|
|
|
|
for(auto i = std::begin(token68str); i != std::end(token68str); ++i) {
|
|
|
|
|
switch(*i) {
|
|
|
|
|
case '-':
|
|
|
|
|
*i = '+';
|
|
|
|
|
break;
|
|
|
|
|
case '_':
|
|
|
|
|
*i = '/';
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2013-11-09 08:18:01 +01:00
|
|
|
|
if(token68str.size() & 0x3) {
|
|
|
|
|
token68str.append(4 - (token68str.size() & 0x3), '=');
|
|
|
|
|
}
|
2013-08-03 11:51:01 +02:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-27 17:09:46 +02:00
|
|
|
|
void inp_strlower(std::string& s)
|
|
|
|
|
{
|
|
|
|
|
for(auto i = std::begin(s); i != std::end(s); ++i) {
|
|
|
|
|
if('A' <= *i && *i <= 'Z') {
|
|
|
|
|
*i = (*i) - 'A' + 'a';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-01-08 17:27:56 +01:00
|
|
|
|
namespace {
|
|
|
|
|
// Calculates Damerau–Levenshtein distance between c-string a and b
|
|
|
|
|
// with given costs. swapcost, subcost, addcost and delcost are cost
|
|
|
|
|
// to swap 2 adjacent characters, substitute characters, add character
|
|
|
|
|
// and delete character respectively.
|
|
|
|
|
int levenshtein
|
|
|
|
|
(const char* a,
|
|
|
|
|
const char* b,
|
|
|
|
|
int swapcost,
|
|
|
|
|
int subcost,
|
|
|
|
|
int addcost,
|
|
|
|
|
int delcost)
|
|
|
|
|
{
|
|
|
|
|
int alen = strlen(a);
|
|
|
|
|
int blen = strlen(b);
|
|
|
|
|
auto dp = std::vector<std::vector<int>>(3, std::vector<int>(blen+1));
|
|
|
|
|
for(int i = 0; i <= blen; ++i) {
|
|
|
|
|
dp[1][i] = i;
|
|
|
|
|
}
|
|
|
|
|
for(int i = 1; i <= alen; ++i) {
|
|
|
|
|
dp[0][0] = i;
|
|
|
|
|
for(int j = 1; j <= blen; ++j) {
|
|
|
|
|
dp[0][j] = dp[1][j-1]+(a[i-1] == b[j-1] ? 0 : subcost);
|
|
|
|
|
if(i >= 2 && j >= 2 && a[i-1] != b[j-1] &&
|
|
|
|
|
a[i-2] == b[j-1] && a[i-1] == b[j-2]) {
|
|
|
|
|
dp[0][j] = std::min(dp[0][j], dp[2][j-2]+swapcost);
|
|
|
|
|
}
|
|
|
|
|
dp[0][j] = std::min(dp[0][j],
|
|
|
|
|
std::min(dp[1][j]+delcost, dp[0][j-1]+addcost));
|
|
|
|
|
}
|
|
|
|
|
std::rotate(std::begin(dp), std::begin(dp)+2, std::end(dp));
|
|
|
|
|
}
|
|
|
|
|
return dp[1][blen];
|
|
|
|
|
}
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
void show_candidates(const char *unkopt, option *options)
|
|
|
|
|
{
|
|
|
|
|
for(; *unkopt == '-'; ++unkopt);
|
|
|
|
|
if(*unkopt == '\0') {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2014-01-13 15:51:10 +01:00
|
|
|
|
int prefix_match = 0;
|
2014-01-13 15:29:10 +01:00
|
|
|
|
auto unkoptlen = strlen(unkopt);
|
2014-01-08 17:27:56 +01:00
|
|
|
|
auto cands = std::vector<std::pair<int, const char*>>();
|
|
|
|
|
for(size_t i = 0; options[i].name != nullptr; ++i) {
|
2014-01-13 15:51:10 +01:00
|
|
|
|
auto optnamelen = strlen(options[i].name);
|
|
|
|
|
// Use cost 0 for prefix match
|
|
|
|
|
if(istartsWith(options[i].name, options[i].name + optnamelen,
|
|
|
|
|
unkopt, unkopt + unkoptlen)) {
|
|
|
|
|
if(optnamelen == unkoptlen) {
|
|
|
|
|
// Exact match, then we don't show any condidates.
|
|
|
|
|
return ;
|
|
|
|
|
}
|
|
|
|
|
++prefix_match;
|
|
|
|
|
cands.emplace_back(0, options[i].name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// Use cost 0 for suffix match, but match at least 3 characters
|
|
|
|
|
if(unkoptlen >= 3 &&
|
|
|
|
|
iendsWith(options[i].name, options[i].name + optnamelen,
|
|
|
|
|
unkopt, unkopt + unkoptlen)) {
|
2014-01-08 17:27:56 +01:00
|
|
|
|
cands.emplace_back(0, options[i].name);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// cost values are borrowed from git, help.c.
|
|
|
|
|
int sim = levenshtein(unkopt, options[i].name, 0, 2, 1, 3);
|
|
|
|
|
cands.emplace_back(sim, options[i].name);
|
|
|
|
|
}
|
2014-01-13 15:51:10 +01:00
|
|
|
|
if(prefix_match == 1 || cands.empty()) {
|
2014-01-08 17:27:56 +01:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::sort(std::begin(cands), std::end(cands));
|
|
|
|
|
int threshold = cands[0].first;
|
|
|
|
|
// threshold value is a magic value.
|
|
|
|
|
if(threshold > 6) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
std::cerr << "\nDid you mean:\n";
|
|
|
|
|
for(auto& item : cands) {
|
|
|
|
|
if(item.first > threshold) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
std::cerr << "\t--" << item.second << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-02-27 13:47:04 +01:00
|
|
|
|
bool has_uri_field(const http_parser_url &u, http_parser_url_fields field)
|
|
|
|
|
{
|
|
|
|
|
return u.field_set & (1 << field);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool fieldeq(const char *uri1, const http_parser_url &u1,
|
|
|
|
|
const char *uri2, const http_parser_url &u2,
|
|
|
|
|
http_parser_url_fields field)
|
|
|
|
|
{
|
|
|
|
|
if(!has_uri_field(u1, field)) {
|
|
|
|
|
if(!has_uri_field(u2, field)) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else if(!has_uri_field(u2, field)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if(u1.field_data[field].len != u2.field_data[field].len) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return memcmp(uri1+u1.field_data[field].off,
|
|
|
|
|
uri2+u2.field_data[field].off,
|
|
|
|
|
u1.field_data[field].len) == 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool fieldeq(const char *uri, const http_parser_url &u,
|
|
|
|
|
http_parser_url_fields field,
|
|
|
|
|
const char *t)
|
|
|
|
|
{
|
|
|
|
|
if(!has_uri_field(u, field)) {
|
|
|
|
|
if(!t[0]) {
|
|
|
|
|
return true;
|
|
|
|
|
} else {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
} else if(!t[0]) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
int i, len = u.field_data[field].len;
|
|
|
|
|
const char *p = uri+u.field_data[field].off;
|
|
|
|
|
for(i = 0; i < len && t[i] && p[i] == t[i]; ++i);
|
|
|
|
|
return i == len && !t[i];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string get_uri_field(const char *uri, const http_parser_url &u,
|
|
|
|
|
http_parser_url_fields field)
|
|
|
|
|
{
|
|
|
|
|
if(util::has_uri_field(u, field)) {
|
|
|
|
|
return std::string(uri+u.field_data[field].off,
|
|
|
|
|
u.field_data[field].len);
|
|
|
|
|
} else {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint16_t get_default_port(const char *uri, const http_parser_url &u)
|
|
|
|
|
{
|
|
|
|
|
if(util::fieldeq(uri, u, UF_SCHEMA, "https")) {
|
|
|
|
|
return 443;
|
|
|
|
|
} else if(util::fieldeq(uri, u, UF_SCHEMA, "http")) {
|
|
|
|
|
return 80;
|
|
|
|
|
} else {
|
|
|
|
|
return 443;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool porteq(const char *uri1, const http_parser_url &u1,
|
|
|
|
|
const char *uri2, const http_parser_url &u2)
|
|
|
|
|
{
|
|
|
|
|
uint16_t port1, port2;
|
|
|
|
|
port1 = util::has_uri_field(u1, UF_PORT) ?
|
|
|
|
|
u1.port : get_default_port(uri1, u1);
|
|
|
|
|
port2 = util::has_uri_field(u2, UF_PORT) ?
|
|
|
|
|
u2.port : get_default_port(uri2, u2);
|
|
|
|
|
return port1 == port2;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void write_uri_field(std::ostream& o,
|
|
|
|
|
const char *uri, const http_parser_url &u,
|
|
|
|
|
http_parser_url_fields field)
|
|
|
|
|
{
|
|
|
|
|
if(util::has_uri_field(u, field)) {
|
|
|
|
|
o.write(uri+u.field_data[field].off, u.field_data[field].len);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-04 16:23:33 +01:00
|
|
|
|
EvbufferBuffer::EvbufferBuffer()
|
|
|
|
|
: evbuffer_(nullptr),
|
|
|
|
|
buf_(nullptr),
|
|
|
|
|
bufmax_(0),
|
|
|
|
|
buflen_(0)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax)
|
|
|
|
|
: evbuffer_(evbuffer),
|
|
|
|
|
buf_(buf),
|
|
|
|
|
bufmax_(bufmax),
|
|
|
|
|
buflen_(0)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax)
|
|
|
|
|
{
|
|
|
|
|
evbuffer_ = evbuffer;
|
|
|
|
|
buf_ = buf;
|
|
|
|
|
bufmax_ = bufmax;
|
|
|
|
|
buflen_ = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int EvbufferBuffer::flush()
|
|
|
|
|
{
|
|
|
|
|
int rv;
|
2014-03-15 08:23:12 +01:00
|
|
|
|
if(buflen_ > 0) {
|
|
|
|
|
rv = evbuffer_add(evbuffer_, buf_, buflen_);
|
|
|
|
|
if(rv == -1) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
buflen_ = 0;
|
2014-03-04 16:23:33 +01:00
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int EvbufferBuffer::add(const uint8_t *data, size_t datalen)
|
|
|
|
|
{
|
|
|
|
|
int rv;
|
|
|
|
|
if(buflen_ + datalen > bufmax_) {
|
2014-03-15 08:23:12 +01:00
|
|
|
|
if(buflen_ > 0) {
|
|
|
|
|
rv = evbuffer_add(evbuffer_, buf_, buflen_);
|
|
|
|
|
if(rv == -1) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
buflen_ = 0;
|
2014-03-04 16:23:33 +01:00
|
|
|
|
}
|
|
|
|
|
if(datalen > bufmax_) {
|
|
|
|
|
rv = evbuffer_add(evbuffer_, data, datalen);
|
|
|
|
|
if(rv == -1) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
memcpy(buf_ + buflen_, data, datalen);
|
|
|
|
|
buflen_ += datalen;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
size_t EvbufferBuffer::get_buflen() const
|
|
|
|
|
{
|
|
|
|
|
return buflen_;
|
|
|
|
|
}
|
|
|
|
|
|
2014-03-15 07:32:38 +01:00
|
|
|
|
bool numeric_host(const char *hostname)
|
|
|
|
|
{
|
|
|
|
|
struct addrinfo hints;
|
|
|
|
|
struct addrinfo* res;
|
|
|
|
|
memset(&hints, 0, sizeof(hints));
|
|
|
|
|
hints.ai_family = AF_UNSPEC;
|
|
|
|
|
hints.ai_flags = AI_NUMERICHOST;
|
|
|
|
|
if(getaddrinfo(hostname, nullptr, &hints, &res)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
freeaddrinfo(res);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2014-07-05 11:22:40 +02:00
|
|
|
|
int reopen_log_file(const char *path)
|
|
|
|
|
{
|
|
|
|
|
auto fd = open(path, O_WRONLY | O_APPEND | O_CREAT,
|
2014-07-05 15:41:53 +02:00
|
|
|
|
S_IRUSR | S_IWUSR | S_IRGRP);
|
2014-07-05 11:22:40 +02:00
|
|
|
|
|
|
|
|
|
if(fd == -1) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return fd;
|
|
|
|
|
}
|
|
|
|
|
|
2012-01-29 16:34:10 +01:00
|
|
|
|
} // namespace util
|
|
|
|
|
|
2013-07-12 17:19:03 +02:00
|
|
|
|
} // namespace nghttp2
|