I am trying to learn about how a HTTP client works in Java. I am trying to build my own client that will make a request to a web server for a php file.
Currently when I make the request the server gives me the following error:
HTTP/1.1 400 Bad Request
However, I am able to access the file from within a browser no problem. I don't know what I could be doing wrong but I can't figure it out. Below is the code for my HTTP Client class:
public class MyHttpClient {
MyHttpRequest request;
String host;
public MyHttpResponse execute(MyHttpRequest request) throws IOException {
//Creating the response object
MyHttpResponse response = new MyHttpResponse();
//Get web server host and port from request.
String host = request.getHost();
int port = request.getPort();
//Check 1: HOST AND PORT NAME CORRECT!
System.out.println("host: " + host + " port: " + String.valueOf(port));
//Get resource path on web server from requests.
String path = request.getPath();
//Check 2: ENSURE PATH IS CORRECT!
System.out.println("path: " + path);
//Open connection to the web server
Socket s = new Socket(host, port);
//Get Socket input stream and wrap it in Buffered Reader so it can be read line by line.
BufferedReader inFromServer = new BufferedReader(new InputStreamReader(s.getInputStream()));
//Get Socket output stream and wrap it in a Buffered Writer so it can be written to line by line.
PrintWriter outToServer = new PrintWriter(s.getOutputStream(),true);
//Get request method
String method = request.getMethod();
//Check 3: ENSURE REQUEST IS CORRECT GET/POST!
System.out.println("Method: " + method);
//GET REQUEST
if(method.equalsIgnoreCase("GET")){
//Send request to server
outToServer.println("GET " + path + " HTTP/1.1 " + "\r\n");
String line = inFromServer.readLine();
System.out.println("Line: " + line);
}
//Returning the response
return response;
}
}
If anyone could shed some light on this issue I'd appreciate it very much! Thanks.
New Request To Server:
outToServer.print("GET " + path+ " HTTP/1.1" + "\r\n");
outToServer.print("Host: " + host + "\r\n");
outToServer.print("\r\n");
Response:
Method: GET
line: <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
line: <html><head>
line: <title>400 Bad Request</title>
line: </head><body>
line: <h1>Bad Request</h1>
line: <p>Your browser sent a request that this server could not understand.<br />
line: </p>
line: <hr>
line: <address>Apache Server at default.secureserver.net Port 80</address>
line: </body></html>
line: null
Do not use PrintWriter. You have to write ascii characters.
s.getOutputStream().write(("GET " + path + " HTTP/1.1\r\n\r\n").getBytes("ASCII"));
I think you need at least to add the Host header in the request.
Example taken from http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol
GET /index.html HTTP/1.1
Host: www.example.com
After the headers are complete you also need to transfer an extra \r\n so the server knows that the request is complete.
Do not use println but print. println adds another \n to every line causing the lines to be terminated with \r\n\n.
Related
I am sending data to grpc service and getting error message in return:
Encountered end-of-stream mid-frame
What does this mean. the connection was interrupted or something else like not enough data sent across. Was it a failure of my client to send enough data of the message over or was it some connection break in the middle of processing. I dont have enough information from this.
If you dont know whats wrong here just tell me if it means the connection closed too early during processing or the datafeed was just not as long as expected but there was no connection problem.
I am using this filter from Envoy proxy (Lyft):
I am using this bridge from Envoy:
https://www.envoyproxy.io/docs/envoy/latest/configuration/http_filters/grpc_http1_bridge_filter
It asks for zero byte up front and 4 bytes with big indian of the length.
For me its a long ugly and meaningless message:
Jul 23, 2019 2:26:06 PM io.grpc.netty.shaded.io.grpc.netty.NettyServerStream$TransportState deframeFailed
WARNING: Exception processing message
io.grpc.StatusRuntimeException: INTERNAL: Encountered end-of-stream mid-frame
at io.grpc.Status.asRuntimeException(Status.java:524)
at io.grpc.internal.AbstractServerStream$TransportState.deframerClosed(AbstractServerStream.java:238)
at io.grpc.netty.shaded.io.grpc.netty.NettyServerStream$TransportState.deframerClosed(NettyServerStream.java:155)
at io.grpc.internal.MessageDeframer.close(MessageDeframer.java:229)
at io.grpc.internal.MessageDeframer.deliver(MessageDeframer.java:296)
at io.grpc.internal.MessageDeframer.request(MessageDeframer.java:161)
at io.grpc.internal.AbstractStream$TransportState.requestMessagesFromDeframer(AbstractStream.java:205)
at io.grpc.netty.shaded.io.grpc.netty.NettyServerStream$Sink$1.run(NettyServerStream.java:100)
at io.grpc.netty.shaded.io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:163)
at io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:404)
at io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:333)
at io.grpc.netty.shaded.io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:905)
at io.grpc.netty.shaded.io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.lang.Thread.run(Thread.java:748)
14:26:06.445 [grpc-default-worker-ELG-3-2] DEBUG io.grpc.netty.shaded.io.grpc.netty.NettyServerHandler - [id: 0xd01ed34c, L:/127.0.0.1:9009 - R:/127.0.0.1:48042] OUTBOUND RST_STREAM: streamId=45 errorCode=8```
Is there something wrong with the client?
//Define a postRequest request
HttpPost postRequest = new HttpPost("http://10.10.xx.xx:31380/com.test.EchoService/echo");
//Set the API media type in http content-type header
postRequest.addHeader("content-type", "application/grpc");
int messageLength=EchoRequest.newBuilder()
.setMessage("Hello"+ ": " + Thread.currentThread().getName())
.build().getMessageBytes().toByteArray().length;
byte[] lengthBytes = ByteBuffer.allocate(4).putInt(messageLength).array();
byte[] zeroByte = {0};
byte[] messageBytes = EchoRequest.newBuilder()
.setMessage("Hello" + ": " + Thread.currentThread().getName())
.build().getMessageBytes().toByteArray();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
baos.write(zeroByte);
baos.write(lengthBytes);
baos.write(messageBytes);
byte[] c = baos.toByteArray();
//Set the request post body
StringEntity userEntity = new StringEntity(content);
ByteArrayEntity bae = new ByteArrayEntity(baos.toByteArray());
postRequest.setEntity(userEntity);
//Send the request; It will immediately return the response in HttpResponse object if any
HttpResponse response = httpClient.execute(postRequest);
//verify the valid error code first
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 201)
{
throw new RuntimeException("Failed with HTTP error code : " + statusCode);
}
the error message means, the server received partial data, and it doesn't expect more data coming since the end of stream is true.
based on the error message, the length is probably larger than actual proto payload.
I'm using a NodeMCU and want to log data to my local Web2Py server.
The request: "http://minion.local:8000/ardulog/default/add/6476366/45643" works fine from the browser and returns a record id.
My Arduino can connect to my server but don't get any return data error or otherwise and nothing appears in my database.
// This will send the request to the server
samptime = millis();
rpm = (samptime + 333) % 96789;
String request = "10.0.0.244:8000/ardulog/default/add/"+String(samptime)+"/"+String(rpm)+" HTTP/1.1";
Serial.println("\ntrying: ");
Serial.println("GET " + request);
Serial.println("host: minion.local");
client.println("GET " + request);
client.println("host: minion.local");
// if there are incoming bytes available
// from the server, read them and print them:
while (client.available()) {
char c = client.read();
Serial.print(c);
}
Serial.println("closing connection");
client.stop();
I've tried every variant I can think of but get only the following:
connecting to minion.local
[hostByName] request IP for: minion.local
[hostByName] Host: minion.local IP: 10.0.0.244
Requesting:
GET 10.0.0.244:8000/ardulog/default/add/112725/16269 HTTP/1.1
host: minion.local
closing connection
wait 5 sec...
Why am I not reading anything retuned from the server?
SOLVED! Though I was unsuccessful POSTing to Google Sheets, simply changing the word from GET to POST worked with Web2Py without sending any body data:
if(client.connect(host,port))
client.println("POST /ardulog/default/add/" + String(samptime)+ "/" + String(rpm) + " HTTP/1.1");
(still not receiving a result page from the server though)
I have a setup which uses the ESP8266 12E and it opens a web server at a specific port 200. I have used the port forwarding to route the incoming data to this server .And I have used the duckdns to register the IP and call the duckdns domain to trigger the ESP.
This works fine and I am able to trigger using the following
http://mydomain.duckdns.org:200/parseIFTTT
Using the postman tool, with the contentType as plain/text and the method as POST what ever contents I pass are getting parsed by parseIFTTT method in the ESP
void parseIFTTT() {
String message;
message += server.args();
message += "\n";
for (uint8_t i = 0; i < server.args(); i++) {
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
}
Serial.println(message);
server.send(200, "text/plain", "Success");
}
But when tried to integrate with IFTTT for any Facebook or gmail events, I am not able to parse the data from IFTTT.
The request goes to ESP8266 but the request data I am not able to parse.
The following is the request :
URL : http://mydomain.duckdns.org:200/parseIFTTT
Method : POST
Content Type: text/plain
Body : {{Message}}
In the body I have just added the {{Message}} only. In the serial monitor I get the op as blank
1
plain:
I found the issue after a lot of debugging.
The esp8266\hardware\esp8266\2.2.0\libraries\ESP8266WebServer\src\Parsing.cpp
in the core library for the Http server was using the 'Content-Length' and IFTTT was sending the request header with name as "content-length' and hence the content length was not retrieved and the parsed data was not retrieved.
Not sure whether its an issue with the IFTTT where they send this as a lower cased value.
I have some problems with connecting a qt client to an embedded jetty server.
At first, I use the following components:
Qt 4.4.3 (compiled with active openssl support)
jetty 8.8.1
java 6
I know, the versions are not most recent, but because of licencing issues and customer wishes I can not use newer one.
So, the scenario is that a qt client has to send http GET and POST requests to the jetty server. As long I use simple http with the QHttp object it works fine, the problems start when I switch to SSL.
My first try was to use the QSslSocket object for the GET request:
// Load certs + private key to socket
_pSocket = new QSslSocket(this);
_pSocket->setLocalCertificate(_certificate);
_pSocket->setPrivateKey(_privatekey);
_pSocket->addDefaultCaCertificate(_cacertificate);
connect (_pSocket, SIGNAL(encrypted()), this, SLOT(_encrypted()));
_pSocket->connectToHostEncrypted("localhost", 8000);
with the following slot function for the encrypted state:
void TestClient::_encrypted() {
QString _path("/testpath/list");
QByteArray buffer("GET ");
buffer.append(_path).append(" HTTP/1.1\r\n");
_pSocket->write(buffer);
}
Here I have my first problem:
This results in the following string, which is as far as I see compliant to RFC 2616:
"GET /testpath/list HTTP/1.1\r\n"
For some reason, the jetty server has a problem with that, keeping in a loop till the client close the connection because of a time out.
But if I use the following string, it works perfect:
"GET /testpath/list\r\n"
Here is my first question: Do you now an explanation for this behaviour ? I can live with it, but I want to know the reason
My second problem is the POST request, this fails always.
These examples I already tried:
"POST /testpath/receive/\r\n{"data":"hello world ?!"}\r\n"
"POST /testpath/receive/ HTTP/1.1\r\n{"data":"hello world ?!"}\r\n"
"POST /testpath/receive/\r\n\r\n{"data":"hello world ?!"}\r\n"
"POST /testpath/receive/ HTTP/1.1\r\n\r\n{"data":"hello world ?!"}\r\n"
I have the feeling, that the body is every time empty, so my server crashes because he tries to parse an empty string as json.
At least, the following log shows that:
2013-11-19 17:11:51.671, INFO, foo.bar.RepositoryHandler, qtp11155366-16 - /testpath/receive request type : /receive
2013-11-19 17:11:51.811, ERROR, foo.bar.RepositoryHandler, qtp11155366-16 - /testpath/receive missing or unknown elements in JSON request. Check JSON against documentation
2013-11-19 17:11:51.874, WARN, org.eclipse.jetty.server.AbstractHttpConnection, qtp11155366-16 - /testpath/receive /testpath/receive
java.lang.NullPointerException: null
at foo.bar.RepositoryHandler.decodeViewingRequest(RepositoryHandler.java:366) ~[MyServer.jar:na]
at foo.bar.RepositoryHandler.handle(RepositoryHandler.java:182) ~[MyServer.jar:na]
So, all together, I think I have several major errors in my requests. But which ?
My second try was to use the QHttp object and change the QSocket it uses with a QSslSocket I already initiated.
Here's the code of the main function:
QSslSocket* _pSocket;
QHttp* _pHttp;
int _id;
QBuffer* _pBuffer;
QByteArray _data;
_pSocket = new QSslSocket(this);
_pSocket->setLocalCertificate(_certificate);
_pSocket->setPrivateKey(_privatekey);
_pSocket->addDefaultCaCertificate(_cacertificate);
QUrl url;
url.setScheme("https");
url.setHost("localhost");
url.setPort(8001);
url.setPath("/testpath/receive");
connect (_pSocket, SIGNAL(encrypted()), this, SLOT(_encrypted()));
connect(_pHttp,SIGNAL(requestFinished(int,bool)),this,SLOT(_requestFinished(int,bool)));
connect(_pHttp,SIGNAL(done(bool)),this,SLOT(_done(bool)));
_pBuffer = new QBuffer(&_data);
_pHttp->setSocket(_pSocket);
_pSocket->connectToHostEncrypted(strHost, strPort.toInt());
_id = _pHttp->get(url.toString(),_pBuffer);
And the callbacks:
void _requestFinished(int id, bool error) {
if(id = _id)
qDebug() << "data=" << _data;
}
void _encrypted() {
qDebug() << "encrypted";
}
void _done(bool error) {
logInfo() << "_done";
if(_pHttp) {
_pHttp->abort();
delete _pHttp;
_pHttp = 0;
}
if(_pBuffer) {
delete _pBuffer;
_pBuffer = 0;
}
if(_pSocket) {
_pSocket->disconnectFromHost();
delete _pSocket;
_pSocket = 0;
}
}
I think, I only have to change the position of the _pHttp->get call, perhaps in the _encrypted callback, but I'm not sure.
Some good advise ?
Thanks,
Robert
Your HTTP request is incomplete, per RFC2616.
"GET /testpath/list HTTP/1.1\r\n"
That is invalid.
Try this instead.
"GET /testpath/list HTTP/1.1\r\n" + /* request line (required) */
"Host: localhost\r\n" + /* host header (required minimum) */
"\r\n" /* terminating CR + LF (required) */
As outlined in Section 5.1.2
The most common form of Request-URI is that used to identify a
resource on an origin server or gateway. In this case the absolute
path of the URI MUST be transmitted (see section 3.2.1, abs_path) as
the Request-URI, and the network location of the URI (authority) MUST
be transmitted in a Host header field. For example, a client wishing
to retrieve the resource above directly from the origin server would
create a TCP connection to port 80 of the host "www.w3.org" and send
the lines:
GET /pub/WWW/TheProject.html HTTP/1.1
Host: www.w3.org
The Request-URI line and Host header Header are mandated.
I've been working on a BlackBerry post request, and the request is getting sent, but the parameters don't seem to be. Here is my code:
HttpConnection httpConnection = (HttpConnection) Connector.open(url);
httpConnection.setRequestMethod(HttpConnection.POST);
httpConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
URLEncodedPostData encPostData = new URLEncodedPostData("UTF-8", false);
encPostData.append("time", "1314144000");
System.out.println("url: " + httpConnection.getURL());
byte[] postData = encPostData.toString().getBytes("UTF-8");
System.out.println("post data: " + encPostData.toString());
httpConnection.setRequestProperty("Content-length", String.valueOf(postData.length));
System.out.println("url: " + httpConnection.getURL());
System.out.println("message:" + httpConnection.getResponseMessage());
OutputStream os = httpConnection.openOutputStream();
os.write(postData);
os.flush();
os.close();
The response I get from the server(which we set up) is that we didn't send a time stamp. Is there something wrong with my
encPostData.append("time", "1314144000");
code?
Your call to getResponseMessage() before writing the post data is forcing a response before anything has been written on the connection.
System.out.println("message:" + httpConnection.getResponseMessage());
Move that to the end, after the output stream data has been written, and I think it will work better for you.
Make the http connection in read write mode.Might be that is the problem making http connection without mode link
HttpConnection connection = (HttpConnection) Connector.open("url", Connector.READ_WRITE);
See below link for making http connection.
blackberry server connection problem