mirror of
https://github.com/PurpleI2P/i2pd.git
synced 2025-03-22 00:59:08 +01:00
send http headers in original order
This commit is contained in:
parent
7ae38a71cc
commit
66f3bd186f
6 changed files with 113 additions and 66 deletions
|
@ -703,13 +703,13 @@ namespace client
|
||||||
int dest_port = url.port ? url.port : 80;
|
int dest_port = url.port ? url.port : 80;
|
||||||
/* create http request & send it */
|
/* create http request & send it */
|
||||||
i2p::http::HTTPReq req;
|
i2p::http::HTTPReq req;
|
||||||
req.add_header("Host", dest_host);
|
req.AddHeader("Host", dest_host);
|
||||||
req.add_header("User-Agent", "Wget/1.11.4");
|
req.AddHeader("User-Agent", "Wget/1.11.4");
|
||||||
req.add_header("Connection", "close");
|
req.AddHeader("Connection", "close");
|
||||||
if (!m_Etag.empty())
|
if (!m_Etag.empty())
|
||||||
req.add_header("If-None-Match", m_Etag);
|
req.AddHeader("If-None-Match", m_Etag);
|
||||||
if (!m_LastModified.empty())
|
if (!m_LastModified.empty())
|
||||||
req.add_header("If-Modified-Since", m_LastModified);
|
req.AddHeader("If-Modified-Since", m_LastModified);
|
||||||
/* convert url to relative */
|
/* convert url to relative */
|
||||||
url.schema = "";
|
url.schema = "";
|
||||||
url.host = "";
|
url.host = "";
|
||||||
|
|
69
HTTP.cpp
69
HTTP.cpp
|
@ -1,14 +1,15 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2013-2016, The PurpleI2P Project
|
* Copyright (c) 2013-2017, The PurpleI2P Project
|
||||||
*
|
*
|
||||||
* This file is part of Purple i2pd project and licensed under BSD3
|
* This file is part of Purple i2pd project and licensed under BSD3
|
||||||
*
|
*
|
||||||
* See full license text in LICENSE file at top of project tree
|
* See full license text in LICENSE file at top of project tree
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <utility>
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "HTTP.h"
|
#include "HTTP.h"
|
||||||
#include <algorithm>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
|
||||||
namespace i2p {
|
namespace i2p {
|
||||||
|
@ -43,18 +44,16 @@ namespace http {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool parse_header_line(const std::string & line, std::map<std::string, std::string> & headers) {
|
static std::pair<std::string, std::string> parse_header_line(const std::string& line)
|
||||||
|
{
|
||||||
std::size_t pos = 0;
|
std::size_t pos = 0;
|
||||||
std::size_t len = 2; /* strlen(": ") */
|
std::size_t len = 2; /* strlen(": ") */
|
||||||
std::size_t max = line.length();
|
std::size_t max = line.length();
|
||||||
if ((pos = line.find(": ", pos)) == std::string::npos)
|
if ((pos = line.find(": ", pos)) == std::string::npos)
|
||||||
return false;
|
return std::make_pair("", "");
|
||||||
while ((pos + len) < max && isspace(line.at(pos + len)))
|
while ((pos + len) < max && isspace(line.at(pos + len)))
|
||||||
len++;
|
len++;
|
||||||
std::string name = line.substr(0, pos);
|
return std::make_pair(line.substr(0, pos), line.substr(pos + len));
|
||||||
std::string value = line.substr(pos + len);
|
|
||||||
headers[name] = value;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gen_rfc1123_date(std::string & out) {
|
void gen_rfc1123_date(std::string & out) {
|
||||||
|
@ -247,9 +246,14 @@ namespace http {
|
||||||
uri = tokens[1];
|
uri = tokens[1];
|
||||||
version = tokens[2];
|
version = tokens[2];
|
||||||
expect = HEADER_LINE;
|
expect = HEADER_LINE;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
std::string line = str.substr(pos, eol - pos);
|
std::string line = str.substr(pos, eol - pos);
|
||||||
if (!parse_header_line(line, headers))
|
auto p = parse_header_line(line);
|
||||||
|
if (p.first.length () > 0)
|
||||||
|
headers.push_back (p);
|
||||||
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pos = eol + strlen(CRLF);
|
pos = eol + strlen(CRLF);
|
||||||
|
@ -259,11 +263,11 @@ namespace http {
|
||||||
return eoh + strlen(HTTP_EOH);
|
return eoh + strlen(HTTP_EOH);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HTTPReq::write(std::ostream & o) {
|
void HTTPReq::write(std::ostream & o)
|
||||||
|
{
|
||||||
o << method << " " << uri << " " << version << CRLF;
|
o << method << " " << uri << " " << version << CRLF;
|
||||||
for (auto & h : headers) {
|
for (auto & h : headers)
|
||||||
o << h.first << ": " << h.second << CRLF;
|
o << h.first << ": " << h.second << CRLF;
|
||||||
}
|
|
||||||
o << CRLF;
|
o << CRLF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,6 +278,40 @@ namespace http {
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HTTPReq::AddHeader (const std::string& name, const std::string& value)
|
||||||
|
{
|
||||||
|
headers.push_back (std::make_pair(name, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPReq::UpdateHeader (const std::string& name, const std::string& value)
|
||||||
|
{
|
||||||
|
for (auto& it : headers)
|
||||||
|
if (it.first == name)
|
||||||
|
{
|
||||||
|
it.second = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void HTTPReq::RemoveHeader (const std::string& name)
|
||||||
|
{
|
||||||
|
for (auto it = headers.begin (); it != headers.end ();)
|
||||||
|
{
|
||||||
|
if (!it->first.compare(0, name.length (), name))
|
||||||
|
it = headers.erase (it);
|
||||||
|
else
|
||||||
|
it++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string HTTPReq::GetHeader (const std::string& name) const
|
||||||
|
{
|
||||||
|
for (auto& it : headers)
|
||||||
|
if (it.first == name)
|
||||||
|
return it.second;
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
bool HTTPRes::is_chunked() {
|
bool HTTPRes::is_chunked() {
|
||||||
auto it = headers.find("Transfer-Encoding");
|
auto it = headers.find("Transfer-Encoding");
|
||||||
if (it == headers.end())
|
if (it == headers.end())
|
||||||
|
@ -335,7 +373,10 @@ namespace http {
|
||||||
expect = HEADER_LINE;
|
expect = HEADER_LINE;
|
||||||
} else {
|
} else {
|
||||||
std::string line = str.substr(pos, eol - pos);
|
std::string line = str.substr(pos, eol - pos);
|
||||||
if (!parse_header_line(line, headers))
|
auto p = parse_header_line(line);
|
||||||
|
if (p.first.length () > 0)
|
||||||
|
headers.insert (p);
|
||||||
|
else
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pos = eol + strlen(CRLF);
|
pos = eol + strlen(CRLF);
|
||||||
|
|
13
HTTP.h
13
HTTP.h
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <list>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -54,7 +55,8 @@ namespace http {
|
||||||
std::string to_string ();
|
std::string to_string ();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HTTPMsg {
|
struct HTTPMsg
|
||||||
|
{
|
||||||
std::map<std::string, std::string> headers;
|
std::map<std::string, std::string> headers;
|
||||||
|
|
||||||
void add_header(const char *name, std::string & value, bool replace = false);
|
void add_header(const char *name, std::string & value, bool replace = false);
|
||||||
|
@ -65,7 +67,9 @@ namespace http {
|
||||||
long int content_length();
|
long int content_length();
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HTTPReq : HTTPMsg {
|
struct HTTPReq
|
||||||
|
{
|
||||||
|
std::list<std::pair<std::string, std::string> > headers;
|
||||||
std::string version;
|
std::string version;
|
||||||
std::string method;
|
std::string method;
|
||||||
std::string uri;
|
std::string uri;
|
||||||
|
@ -82,9 +86,12 @@ namespace http {
|
||||||
|
|
||||||
/** @brief Serialize HTTP request to string */
|
/** @brief Serialize HTTP request to string */
|
||||||
std::string to_string();
|
std::string to_string();
|
||||||
|
|
||||||
void write(std::ostream & o);
|
void write(std::ostream & o);
|
||||||
|
|
||||||
|
void AddHeader (const std::string& name, const std::string& value);
|
||||||
|
void UpdateHeader (const std::string& name, const std::string& value);
|
||||||
|
void RemoveHeader (const std::string& name);
|
||||||
|
std::string GetHeader (const std::string& name) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HTTPRes : HTTPMsg {
|
struct HTTPRes : HTTPMsg {
|
||||||
|
|
|
@ -200,26 +200,16 @@ namespace proxy {
|
||||||
void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq & req)
|
void HTTPReqHandler::SanitizeHTTPRequest(i2p::http::HTTPReq & req)
|
||||||
{
|
{
|
||||||
/* drop common headers */
|
/* drop common headers */
|
||||||
req.del_header("Referer");
|
req.RemoveHeader ("Referer");
|
||||||
req.del_header("Via");
|
req.RemoveHeader("Via");
|
||||||
req.del_header("Forwarded");
|
req.RemoveHeader("Forwarded");
|
||||||
/* drop proxy-disclosing headers */
|
/* drop proxy-disclosing headers */
|
||||||
std::vector<std::string> toErase;
|
req.RemoveHeader("X-Forwarded");
|
||||||
for (const auto& it : req.headers) {
|
req.RemoveHeader("Proxy-");
|
||||||
if (it.first.compare(0, 12, "X-Forwarded-") == 0) {
|
|
||||||
toErase.push_back(it.first);
|
|
||||||
} else if (it.first.compare(0, 6, "Proxy-") == 0) {
|
|
||||||
toErase.push_back(it.first);
|
|
||||||
} else {
|
|
||||||
/* allow */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const auto& header : toErase) {
|
|
||||||
req.headers.erase(header);
|
|
||||||
}
|
|
||||||
/* replace headers */
|
/* replace headers */
|
||||||
req.add_header("Connection", "close", true); /* keep-alive conns not supported yet */
|
req.UpdateHeader("User-Agent", "MYOB/6.66 (AN/ON)");
|
||||||
req.add_header("User-Agent", "MYOB/6.66 (AN/ON)", true); /* privacy */
|
/* add headers */
|
||||||
|
req.AddHeader("Connection", "close"); /* keep-alive conns not supported yet */
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -263,29 +253,36 @@ namespace proxy {
|
||||||
std::string dest_host = m_RequestURL.host;
|
std::string dest_host = m_RequestURL.host;
|
||||||
uint16_t dest_port = m_RequestURL.port;
|
uint16_t dest_port = m_RequestURL.port;
|
||||||
/* always set port, even if missing in request */
|
/* always set port, even if missing in request */
|
||||||
if (!dest_port) {
|
if (!dest_port)
|
||||||
dest_port = (m_RequestURL.schema == "https") ? 443 : 80;
|
dest_port = (m_RequestURL.schema == "https") ? 443 : 80;
|
||||||
}
|
|
||||||
/* detect dest_host, set proper 'Host' header in upstream request */
|
/* detect dest_host, set proper 'Host' header in upstream request */
|
||||||
auto h = m_ClientRequest.headers.find("Host");
|
if (dest_host != "")
|
||||||
if (dest_host != "") {
|
{
|
||||||
/* absolute url, replace 'Host' header */
|
/* absolute url, replace 'Host' header */
|
||||||
std::string h = dest_host;
|
std::string h = dest_host;
|
||||||
if (dest_port != 0 && dest_port != 80)
|
if (dest_port != 0 && dest_port != 80)
|
||||||
h += ":" + std::to_string(dest_port);
|
h += ":" + std::to_string(dest_port);
|
||||||
m_ClientRequest.add_header("Host", h, true);
|
m_ClientRequest.UpdateHeader("Host", h);
|
||||||
} else if (h != m_ClientRequest.headers.end()) {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto h = m_ClientRequest.GetHeader ("Host");
|
||||||
|
if (h.length () > 0)
|
||||||
|
{
|
||||||
/* relative url and 'Host' header provided. transparent proxy mode? */
|
/* relative url and 'Host' header provided. transparent proxy mode? */
|
||||||
i2p::http::URL u;
|
i2p::http::URL u;
|
||||||
std::string t = "http://" + h->second;
|
std::string t = "http://" + h;
|
||||||
u.parse(t);
|
u.parse(t);
|
||||||
dest_host = u.host;
|
dest_host = u.host;
|
||||||
dest_port = u.port;
|
dest_port = u.port;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* relative url and missing 'Host' header */
|
/* relative url and missing 'Host' header */
|
||||||
GenericProxyError("Invalid request", "Can't detect destination host from request");
|
GenericProxyError("Invalid request", "Can't detect destination host from request");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* check dest_host really exists and inside I2P network */
|
/* check dest_host really exists and inside I2P network */
|
||||||
i2p::data::IdentHash identHash;
|
i2p::data::IdentHash identHash;
|
||||||
|
|
|
@ -714,9 +714,11 @@ namespace http {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
/* method #2: 'Authorization' header sent */
|
/* method #2: 'Authorization' header sent */
|
||||||
if (req.headers.count("Authorization") > 0) {
|
auto provided = req.GetHeader ("Authorization");
|
||||||
|
if (provided.length () > 0)
|
||||||
|
{
|
||||||
bool result = false;
|
bool result = false;
|
||||||
std::string provided = req.headers.find("Authorization")->second;
|
|
||||||
std::string expected = user + ":" + pass;
|
std::string expected = user + ":" + pass;
|
||||||
size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1;
|
size_t b64_sz = i2p::data::Base64EncodingBufferSize(expected.length()) + 1;
|
||||||
char * b64_creds = new char[b64_sz];
|
char * b64_creds = new char[b64_sz];
|
||||||
|
|
|
@ -517,8 +517,8 @@ namespace data
|
||||||
LogPrint (eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
|
LogPrint (eLogDebug, "Reseed: Connected to ", url.host, ":", url.port);
|
||||||
i2p::http::HTTPReq req;
|
i2p::http::HTTPReq req;
|
||||||
req.uri = url.to_string();
|
req.uri = url.to_string();
|
||||||
req.add_header("User-Agent", "Wget/1.11.4");
|
req.AddHeader("User-Agent", "Wget/1.11.4");
|
||||||
req.add_header("Connection", "close");
|
req.AddHeader("Connection", "close");
|
||||||
s.write_some (boost::asio::buffer (req.to_string()));
|
s.write_some (boost::asio::buffer (req.to_string()));
|
||||||
// read response
|
// read response
|
||||||
std::stringstream rs;
|
std::stringstream rs;
|
||||||
|
|
Loading…
Add table
Reference in a new issue