14 #include "../../stdafx.h" 15 #include "../../debug.h" 16 #include "../../rev.h" 17 #include "../network_func.h" 21 #include "../../safeguards.h" 36 HTTPCallback *callback,
const char *host,
const char *url,
37 const char *data,
int depth) :
43 redirect_depth(depth),
46 size_t bufferSize = strlen(url) + strlen(host) + strlen(
GetNetworkRevisionString()) + (data ==
nullptr ? 0 : strlen(data)) + 128;
47 char *buffer =
AllocaM(
char, bufferSize);
49 DEBUG(net, 7,
"[tcp/http] requesting %s%s", host, url);
50 if (data !=
nullptr) {
51 seprintf(buffer, buffer + bufferSize - 1,
"POST %s HTTP/1.0\r\nHost: %s\r\nUser-Agent: OpenTTD/%s\r\nContent-Type: text/plain\r\nContent-Length: %d\r\n\r\n%s\r\n", url, host,
GetNetworkRevisionString(), (
int)strlen(data), data);
56 ssize_t size = strlen(buffer);
57 ssize_t res = send(this->
sock, (
const char*)buffer, size, 0);
74 if (this->
sock != INVALID_SOCKET) closesocket(this->
sock);
75 this->
sock = INVALID_SOCKET;
89 #define return_error(msg) { DEBUG(net, 0, msg); return -1; } 91 static const char *
const NEWLINE =
"\r\n";
93 static const char *
const HTTP_1_0 =
"HTTP/1.0 ";
94 static const char *
const HTTP_1_1 =
"HTTP/1.1 ";
96 static const char *
const LOCATION =
"Location: ";
120 if (strncmp(status,
"200", 3) == 0) {
125 if (length ==
nullptr)
return_error(
"[tcp/http] missing 'content-length' header");
132 char *end_of_line = strstr(length,
NEWLINE);
136 int len = atoi(length);
143 if (len == 0)
return_error(
"[tcp/http] refusing to download 0 bytes");
145 DEBUG(net, 7,
"[tcp/http] downloading %i bytes", len);
149 if (strncmp(status,
"301", 3) != 0 &&
150 strncmp(status,
"302", 3) != 0 &&
151 strncmp(status,
"303", 3) != 0 &&
152 strncmp(status,
"307", 3) != 0) {
157 *strstr(status,
NEWLINE) =
'\0';
158 DEBUG(net, 0,
"[tcp/http] unhandled status reply %s", status);
166 if (uri ==
nullptr)
return_error(
"[tcp/http] missing 'location' header for redirect");
172 char *end_of_line = strstr(uri,
NEWLINE);
175 DEBUG(net, 6,
"[tcp/http] redirecting to %s", uri);
178 if (ret != 0)
return ret;
181 this->
data =
nullptr;
197 char *hname = strstr(uri,
"://");
198 if (hname ==
nullptr)
return_error(
"[tcp/http] invalid location");
202 char *url = strchr(hname,
'/');
203 if (url ==
nullptr)
return_error(
"[tcp/http] invalid location");
208 const char *company =
nullptr;
209 const char *port =
nullptr;
211 if (company !=
nullptr)
return_error(
"[tcp/http] invalid hostname");
235 int err = GET_LAST_ERROR();
236 if (err != EWOULDBLOCK) {
238 if (err != 104)
DEBUG(net, 0,
"recv failed with error %d", err);
264 if (end_of_header ==
nullptr) {
266 DEBUG(net, 0,
"[tcp/http] header too big");
272 if (ret <= 0)
return ret;
307 FD_SET(handler->sock, &read_fd);
310 tv.tv_sec = tv.tv_usec = 0;
311 int n = select(FD_SETSIZE, &read_fd,
nullptr,
nullptr, &tv);
314 for (
auto iter = _http_connections.begin(); iter < _http_connections.end(); ) {
317 if (FD_ISSET(cur->
sock, &read_fd)) {
324 iter = _http_connections.erase(iter);
void ParseConnectionString(const char **company, const char **port, char *connection_string)
Converts a string to ip/port/company Format: IP:port::company.
Connect with a HTTP server and do ONE query.
SOCKET sock
The socket currently connected to.
Basic functions to receive and send HTTP TCP packets.
int CDECL seprintf(char *str, const char *last, const char *format,...)
Safer implementation of snprintf; same as snprintf except:
int Receive()
Handle receiving of HTTP data.
char recv_buffer[4096]
Partially received message.
NetworkHTTPSocketHandler(SOCKET sock, HTTPCallback *callback, const char *host, const char *url, const char *data, int depth)
Start the querying.
static const char *const HTTP_1_0
Preamble for HTTP 1.0 servers.
static const char *const LOCATION
Header for location.
Wrapper for (un)resolved network addresses; there's no reason to transform a numeric IP to a string a...
const char * GetNetworkRevisionString()
Get the network version string used by this build.
#define AllocaM(T, num_elements)
alloca() has to be called in the parent function, so define AllocaM() as a macro
static void HTTPReceive()
Do the receiving for all HTTP connections.
int redirect_depth
The depth of the redirection.
static const char *const CONTENT_LENGTH
Header for the length of the content.
static int Connect(char *uri, HTTPCallback *callback, const char *data=nullptr, int depth=0)
Connect to the given URI.
static const char *const HTTP_1_1
Preamble for HTTP 1.1 servers.
virtual void OnReceiveData(const char *data, size_t length)=0
We're receiving data.
~NetworkHTTPSocketHandler()
Free whatever needs to be freed.
int recv_pos
Current position in buffer.
virtual void OnFailure()=0
An error has occurred and the connection has been closed.
NetworkRecvStatus
Status of a network client; reasons why a client has quit.
const char * data
The (POST) data we might want to forward (to a redirect).
#define lengthof(x)
Return the length of an fixed size array.
static T min(const T a, const T b)
Returns the minimum of two values.
int HandleHeader()
Handle the header of a HTTP reply.
#define DEBUG(name, level,...)
Output a line of debugging information.
Base socket handler for HTTP traffic.
NetworkRecvStatus CloseConnection(bool error=true) override
Close the current connection; for TCP this will be mostly equivalent to Close(), but for UDP it just ...
virtual NetworkRecvStatus CloseConnection(bool error=true)
Close the current connection; for TCP this will be mostly equivalent to Close(), but for UDP it just ...
void CDECL error(const char *s,...)
Error handling for fatal non-user errors.
Callback for when the HTTP handler has something to tell us.
static void free(const void *ptr)
Version of the standard free that accepts const pointers.
static std::vector< NetworkHTTPSocketHandler * > _http_connections
List of open HTTP connections.
HTTPCallback * callback
The callback to call for the incoming data.
static const char *const NEWLINE
End of line marker.
int recv_length
Length of the data still retrieving.
#define return_error(msg)
Helper to simplify the error handling.
static const char *const END_OF_HEADER
End of header marker.
SocketHandler for all network sockets in OpenTTD.