There is a server that response a .png file over http:
#include "server.h"
string Server::header(int contentLength)
{
string h =
"HTTP/1.1 200 OK\n"
"Content-Length: " + boost::lexical_cast<string>(contentLength) + "\n"
"Content-Type: image/png;\n"
"Connection: close\n"
"\n";
return h;
}
string Server::readMap(const string &filename)
{
ifstream file (filename.c_str(), ios::in|ios::binary);
string reply;
char buf[512];
while (file.read(buf, sizeof(buf)).gcount() > 0)
reply.append(buf, file.gcount());
return reply;
}
void Server::run(const string &filename, int port)
{
string data = readMap(filename);
try
{
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port));
for (;;)
{
tcp::socket socket(io_service);
acceptor.accept(socket);
boost::asio::write(socket, boost::asio::buffer(header( data.size() )));
boost::asio::write(socket, boost::asio::buffer(data));
}
}
catch (std::exception& e)
{
cerr << "exception: " << e.what() << endl;
}
}
Every time an error happens:
exception: Connection reset by peer
I can see some part of an image in my browser, and sometimes the image is almost complete, but it never works without the error.
If I use wget it looks like
wget http://localhost:8089
--2012-03-07 12:07:19-- http://localhost:8089/
Resolving localhost... 127.0.0.1
Connecting to localhost|127.0.0.1|:8089... connected.
HTTP request sent, awaiting response... 200 OK
Length: 760032 (742K) [image/png]
Saving to: `index.html'
62% [========================================================> ] 475,136 --.-K/s in 0.002s
2012-03-07 12:07:19 (287 MB/s) - Read error at byte 475136/760032 (Connection reset by peer). Retrying.
--2012-03-07 12:07:20-- (try: 2) http://localhost:8089/
Connecting to localhost|127.0.0.1|:8089... connected.
HTTP request sent, awaiting response... 200 OK
Length: 760032 (742K) [image/png]
Saving to: `index.html'
73% [==================================================================> ] 557,056 --.-K/s in 0.001s
... many failes and finally
--2012-03-07 12:09:01-- (try: 9) http://localhost:8089/
Connecting to localhost|127.0.0.1|:8089... connected.
HTTP request sent, awaiting response... 200 OK
Length: 760032 (742K) [image/png]
Saving to: `index.html'
100%[===========================================================================================>] 760,032 --.-K/s in 0.001s
Any ideas how to fix it?
There are several more complete HTTP-implementations in the ASIO-docs, including static file serving. One way to go would be to reuse some of that sample code for your application.
In this particular case, there's an example of how to correctly open and buffer a file at http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/example/http/server/request_handler.cpp
std::ifstream is(full_path.c_str(), std::ios::in | std::ios::binary);
...
char buf[512];
while (is.read(buf, sizeof(buf)).gcount() > 0)
rep.content.append(buf, is.gcount());
The docs also has examples for actual asynchronous HTTP-implementations. (I assume you're using boost::asio to eventually make it asynchronous?)
You should receive and decode the HTTP request first, and only send the content if that was what was requested. Browsers sometimes request other resources as well; they may get upset if you send something unexpected, or if you send it before they've sent the request.
You also seem to have an off-by-one error in the data size - you put data.size()-1 in the header, and then send all of data. Perhaps this is a partial workaround for the bug in readMap, where you push an extra character after reaching EOF. You would be better off fixing that, by checking for eof() after reading but before pushing the character; or by reading in a less error-prone (and more efficient) manner, such as:
std::copy(std::istreambuf_iterator<char>(file),
std::istreambuf_iterator<char>(),
std::back_inserter(data));
Also, I don't see any reason to copy the vector into a string. vector can also be converted to an asio::buffer.
Your way of reading the file is incorrect for a start.
Not simply that reading one character at a time isn't a great idea, but the loop is wrong. You could use istreambuf_iterator<char> to input or read() with a number of characters with gcount() determining when the read is complete.
Related
I am trying to send HTTPS request to a server and receive the page contents by only using Boost.Asio(not Network.Ts or Beast or others) by these code :
#include <boost/asio.hpp>
#include <boost/asio/ssl.hpp>
#include <iostream>
int main() {
boost::system::error_code ec;
using namespace boost::asio;
// what we need
io_service svc;
ssl::context ctx(ssl::context::method::tlsv1);
ssl::stream<ip::tcp::socket> ssock(svc, ctx);
ip::tcp::endpoint endpoint(boost::asio::ip::make_address("157.90.94.153",ec),443);
ssock.lowest_layer().connect(endpoint);
ssock.handshake(ssl::stream_base::handshake_type::client);
// send request
std::string request("GET /index.html HTTP/1.1\r\n\r\n");
boost::asio::write(ssock, buffer(request));
// read response
std::string response;
do {
char buf[1024];
size_t bytes_transferred = ssock.read_some(buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
} while (!ec);
// print and exit
std::cout << "Response received: '" << response << "'\n";
}
But I keep getting 405 Not Allowed on my local PC and 400 Bad Request on Coliru.
What did I do wrong?
... "GET /index.html HTTP/1.1\r\n\r\n"
This is not a valid HTTP/1.1 request. It must at least also contain a Host field and the value of the field must match the servers expectation, i.e.
"GET /index.html HTTP/1.1\r\nHost: example.com\r\n\r\n"
In general, HTTP might look easy but is actually complex and has several pitfalls. If you really need to do HTTP by your own please study the standard.
I have a Python echo server made in asyncio and a C++ client that makes use of Boost's Asio. While the echo server works properly, the client does not. The client sends a message that is 3000 characters long, but only receives a response that is 512 characters long from the server even though the client is set to listen until EOF.
Server:
import asyncio
async def handle_client(reader, writer):
received = (await reader.read(3000)).decode("utf8")
print(received)
response = received
writer.write(response.encode("utf8"))
await writer.drain()
writer.close()
async def run_server():
server = await asyncio.start_server(handle_client, "localhost", 15555)
async with server:
await server.serve_forever()
asyncio.run(run_server())
Client:
#include <boost/asio.hpp>
#include <string>
#include <iostream>
int main() {
boost::asio::io_context io_context;
boost::asio::ip::tcp::socket socket(io_context);
boost::asio::ip::tcp::resolver resolver(io_context);
socket.connect(boost::asio::ip::tcp::endpoint(boost::asio::ip::address::from_string("127.0.0.1"), 15555));
// This message is 3000 characters long.
std::string message = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
boost::system::error_code error;
boost::asio::write(socket, boost::asio::buffer(message), error);
if (error) {
std::cerr << "error while sending the long message: " << error.message() << "\n";
}
boost::asio::streambuf receive_buffer;
boost::asio::read(socket, receive_buffer, boost::asio::transfer_at_least(1), error);
if (!error || error != boost::asio::error::eof) {
std::string received_data = boost::asio::buffer_cast<const char*>(receive_buffer.data());
std::cout << received_data << "\n";
}
}
The client output looks like this (according to Python, there is only 512 "a"s):
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa²²²²
What seems to be wrong here? If using boost::asio::read with the completion condition boost::asio::transfer_at_least(1) is not the right way to read until EOF, how can I achieve this?
even though the client is set to listen until EOF.
How so? The code
boost::asio::streambuf receive_buffer;
boost::asio::read(socket, receive_buffer, boost::asio::transfer_at_least(1), error);
Specifically tells the read operation may return as soon as the completion condition is met: transfer_at_least(1). So, as soon as a single byte is read, the operation will complete.
Now, since packets on the wirte usually don't carry a single byte, you will get whatever was already in the TCP buffers or is the first packet to arrive.
Simply use boost::asio::transfer_all() instead.
It also looks like the condition is flawed. Did you mean
if (!error || error == boost::asio::error::eof) {
...
}
This question already has an answer here:
Differ between header and content of http server response (sockets)
(1 answer)
Closed 1 year ago.
I'm making this socket HTTP client (very basic). When recv()'ing response data from example.com it works fine and writes it all to a buffer but when I try to revc any bigger amounts of data it stops at around 1500 bytes.
Right now all I'm trying to do is get the response written into the buffer (headers and all). Not trying to parse anything. But that isn't working. It works for a few iterations but then stops or hangs. I'm asking for help identifying the issue with this receive_response() function that causes these behaviors.
This is the function that revc's the HTTP response:
void tcp_client::receive_response(char *buffer) {
int bytes_recv = 0;
int total_bytes_recv = 0;
for (;;) {
bytes_recv = recv(sock, &buffer[total_bytes_recv], CHUNK_SIZE, 0);
if (bytes_recv <= 0) {
break;
} else {
total_bytes_recv += bytes_recv;
}
}
}
The main function:
int main(int argc, char **argv) {
http_client http;
char response[100000] = {0};
http.connect_to_host("go.com", 80);
http.send_request("GET / HTTP/1.1\r\n\r\n");
http.receive_response(response);
std::cout << response << std::endl;
return 0;
}
Thank you
You seem to expect the server to close the connection after the response is transmitted. A typical HTTP 1.1 server doesn't do that by default; they keep the connection open for further requests, unless the client explicitly asks otherwise via Connection: close header.
So, you receive all the data, and then the next recv call is sitting there, waiting for more data to arrive.
An HTTP 1.1 client is expected to detect the end of response via Content-Length header, or by decoding a chunked response as indicated by Transfer-Encoding: chunked header.
I am implementing an HTTP File download client using Boost ASIO. I am using the async_read operation. The problem I am facing is in the async_read I am receiving the EOF before receiving the full content (i.e Content-Length), this is happening irrespective of the content size. Given is my read operation
void Http::ResumableAsyncDownload::read_content(const boost::system::error_code& err, size_t _size)
{
try {
if ( !err)
{
received_bytes += _size;
if ( ofs_.is_open() ) {
// Write all of the data that has been read so far.
ofs_ << &response_;
} else {
ofs_.open(std::string(params_.tempdir + "/" + params_.partnumber).c_str());
if ( ofs_.is_open() ) {
ofs_ << &response_;
} else {
DEBUG_MSG("Error while opening file to store downloaded data. File Path = %s\n", std::string(params_.tempdir + "/" + params_.partnumber).c_str());
std::cout << ("Unable to open local file for storing downloaded data");
}
}
// Continue reading remaining data until EOF.
boost::asio::async_read(*ssocket_, response_,
boost::asio::transfer_at_least(1),
boost::bind(&ResumableAsyncDownload::read_content, this, _1, _2)
);
}
else if (err != boost::asio::error::eof)
{
DEBUG_MSG("[NET] : Exception in ResumableAsyncDownload in read_content : %s\n", err.message().c_str());
std::cout << ("Asynchronous File Download Error: " + err.message());
}
if(err == boost::asio::error::eof)
{
std::cout << "[RESPONSE] : EOF: We are not breaking connection\n";
ssocket_->shutdown();
delete ssocket_;
ssocket_ = NULL;
delete ctx;
ctx = NULL;
if ( (content_length != received_bytes) && !(params_.get_size) ) {
std::cout << "Failed to receive complete data packet. Content Length = " << content_length << " Received Bytes = " << received_bytes << std::endl;
// ofs_.clear();
}
}
} catch ( std::exception &ex ) {
std::cout << "We have an exception. Exception = " << std::string(ex.what()) << std::endl;
}
}
So for example, the Content-Length is say 292309324, but I will receive EOF before 292309324.
To overcome this problem I have implemented the Chunked download using the HTTP Range header, but in that case for every chunk I request I receive less than the requested chunk, then I re-calculate the next range, it works before the last chunk. I never receive the last chunk and usually the situation is (i.e)
Range for last chunk 227376464-227376641/227376641
Requested Bytes = 178
Response Headers
X-Powered-By: Undertow/1
Content-Range: bytes 227376464-227376641/227376641
Server: WildFly/9
Content-Length: 178
Accept-Ranges: bytes
OperationId: 4a847024-2348-42bd-af7d-3638e41cba4f
Date: Thu, 17 Aug 2017 11:41:18 GMT
Set-Cookie: SERVERID=04-84FRD2128G0US; path=/
Cache-control: private
As you can see, the server is responding with good range of the last chunk but in the read_content is giving EOF.
So in both approaches read_content is not reading the complete data and giving EOF. As I understand EOF is the socket closed by the server and can also cause short-read but isn't my chunked download solution. Shouldn't I receive the last chunked packet in full.
Any thoughts on whats going wrong ? Please also note that I am calling a custom API to download the file but I am seeing the same issue even if I download from some public link (i.e http://mirror.pnl.gov/releases/16.04/ubuntu-16.04.3-desktop-amd64.iso), so I do not think the issue is at my server side. Also note that I do not see this issue if I use the synchronous version of boost::asio::async_read (i.e boost::asio::read). I am using Boost version 1.55 compiled for ARM.
I recommend adding a total byte counter to your Http class size_t bytes_transferred_total_; and ditching err == boost::asio::error::eof. You know the total size as that is part of the original HTTP header Content-Length: <total_body_size> which you've parsed. The amended code would look something like this:
...
if (!err) {
received_bytes += _size;
bytes_transferred_total_ += _size;
...
} else {
...
}
boost::asio::async_read(
*ssocket_, response_, boost::asio::transfer_at_least(1),
boost::bind(&ResumableAsyncDownload::read_content, this, _1, _2));
// continue reading until all data has been received
if (bytes_transferred_total_ >= content_length_from_header_) {
// you've received it all
}
In initializing content_length_from_header_ make sure you understand that it represents the size of the body itself, excluding the header.
Footnote: Instead of boost::bind or std::bind consider using lambdas as they are generally more performant, e.g. allowing compilers to inline them. Unless, of course, you need to exploit bind's dynamic nature.
I am trying to send a get request to acounts.google.com to be able to implement a library for C++ OAuth to learn it.
I get the following code from this post: Creating a HTTPS request using Boost Asio and OpenSSL and modified it as follow:
int main()
{
try
{
std::string request = "/o/oauth2/v2/auth";
boost::system::error_code ec;
using namespace boost::asio;
// what we need
io_service svc;
ssl::context ctx(svc, ssl::context::method::sslv23_client);
ssl::stream<ip::tcp::socket> ssock(svc, ctx);
ip::tcp::resolver resolver(svc);
auto it = resolver.resolve({ "accounts.google.com", "443" }); // https://accouts.google.com:443
boost::asio::connect(ssock.lowest_layer(), it);
ssock.handshake(ssl::stream_base::handshake_type::client);
// send request
std::string fullResuest = "GET " + request + " HTTP/1.1\r\n\r\n";
boost::asio::write(ssock, buffer(fullResuest));
// read response
std::string response;
do
{
char buf[1024];
size_t bytes_transferred = ssock.read_some(buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
std::cout << "Response received: '" << response << "'\n"; // I add this to see what I am getting from the server, so it should not be here.
} while (!ec);
// print and exit
std::cout << "Response received: '" << response << "'\n";
}
catch (const std::exception& e)
{
std::cerr << e.what() << std::endl;
if (std::string const * extra = boost::get_error_info<my_tag_error_info>(e))
{
std::cout << *extra << std::endl;
}
}
}
The problem that I have is as follow:
1- The results that I am getting is not what I am getting when I visit https://accounts.google.com/o/oauth2/v2/auth using a web browser. I essentially getting a message that they can not find the requested URL /o/oauth2/v2/auth
<p>The requested URL <code>/o/oauth2/v2/auth</code> was not found on this server. <ins>ThatÔÇÖs all we know.</ins>
How should I setup the GET commend so I can get the same result that I am getting with a browser?
2- The application hangs getting data from server, apparently the following loop is not right:
do
{
char buf[1024];
size_t bytes_transferred = ssock.read_some(buffer(buf), ec);
if (!ec) response.append(buf, buf + bytes_transferred);
} while (!ec);
What is the correct way of reading responce from the web server which is fast and read all data?
Edit 1
For reference based on accepted answer, I fixed the problem using the correct GET header as shown below:
// send request
std::string fullResuest = "GET " + request + " HTTP/1.1\r\n";
fullResuest+= "Host: " + server + "\r\n";
fullResuest += "Accept: */*\r\n";
fullResuest += "Connection: close\r\n\r\n";
boost::asio::write(ssock, buffer(fullResuest));
A HTTP/1.1 request must have a Host header. A simple experiment with OpenSSL will show the problem, i.e. the missing header:
$ openssl s_client -connect accounts.google.com:443
...
GET /o/oauth2/v2/auth HTTP/1.1
... The requested URL <code>/o/oauth2/v2/auth</code> was not found on this server. <ins>That’s all we know.</ins>
When adding the Host header instead we get a different response:
$ openssl s_client -connect accounts.google.com:443
...
GET /o/oauth2/v2/auth HTTP/1.1
Host: accounts.google.com
... >Required parameter is missing: response_type<
Apart from that HTTP/1.1 implicitly uses HTTP keep-alive, i.e. server and client might keep the connection open after the response is done. This means you should not read until the end of connection but should instead properly parse the HTTP header, extract the Content-length header and/or Transfer-Encoding header and behave according to their values. Or if you want it simpler use HTTP/1.0 instead.
For more information see the HTTP/1.1 standard.