Using BufferedReader.readLine() with sockets and stuck in an infinite loop - tcp

I'm working on a basic TCP server and I've come to the point that I need to handle all incoming lines from the client (the browser) and I've made this loop to detect wether it is GET or HEAD or if-modified-since or whatever I'd want to add to detect.
while ((acumulador = sEntrada.readLine()) != null) {
if (acumulador.startsWith("GET") || acumulador.startsWith("HEAD")) {
recibido = acumulador;
System.out.println("SERVIDOR: Recibido " + acumulador);
//Troceamos la entrada en tres
StringTokenizer tokens = new StringTokenizer(acumulador);
while (tokens.hasMoreTokens()) {
aux.add(tokens.nextToken());
}
tipo = aux.get(0);
archivo = aux.get(1);
version = aux.get(2);
} else if (acumulador.toLowerCase().startsWith("if-modified-since")) {
StringTokenizer tokens = new StringTokenizer(acumulador);
while (tokens.hasMoreTokens()) {
aux2.add(tokens.nextToken());
}
} else {
System.out.println("SERVIDOR: Recibido " + acumulador);
}
}
The problem is that this is the output:
SERVIDOR: Conexion establecida con /127.0.0.1 al puerto 5000
SERVIDOR: Recibido GET / HTTP/1.1
SERVIDOR: Recibido Host: 127.0.0.1:5000
SERVIDOR: Recibido Connection: keep-alive
SERVIDOR: Recibido Cache-Control: max-age=0
SERVIDOR: Recibido Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
SERVIDOR: Recibido User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.97 Safari/537.22
SERVIDOR: Recibido Accept-Encoding: gzip,deflate,sdch
SERVIDOR: Recibido Accept-Language: es,en-US;q=0.8,en;q=0.6
SERVIDOR: Recibido Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
SERVIDOR: Recibido Cookie: __utma=1.1831406279.1361823043.1361997547.1362010032.7; __utmc=1; __utmz=1.1361823043.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
SERVIDOR: Recibido
It looks good, right? It reads everything like I want it to read but the problem is that it does not stop reading, the client never receives anything back from my server because the server never gets out of that loop, like .ReadLine() never got back 'null' and stopped.
What am I doing wrong?

If the server never got null, the client never closed the connection.

Related

Why Materialize template redirect from localhost to 127.0.0.1 after login?

I have added a custom login handler for Github:
const handleLoginGithub = (
params: LoginGithubParams,
errorCallback?: ErrCallbackType
) => {
axios
.get(authConfig.loginGithubEndpoint, { params })
.then(async (res) => {
/*window.localStorage.setItem(
authConfig.storageTokenKeyName,
res.data.accessToken
)*/
const returnUrl = router.query.returnUrl
setUser({ ...res.data })
await window.localStorage.setItem('userData', JSON.stringify(res.data))
//router.replace('/home')
})
.catch((err) => {
if (errorCallback) errorCallback(err)
})
}
There is no redirect from localhost to 127.0.0.1, but it will happen, do you know why?
This is the HTTP message that gos to our backend:
GENERAL:
Request URL: http://localhost:3000/api2/gh-auth-complete?code=f87f5157cbf035a73a50
Request Method: GET
Status Code: 200 OK
Remote Address: [::1]:3000
Referrer Policy: strict-origin-when-cross-origin
RESPONSE HEADER:
connection: close
content-length: 681
content-type: application/json; charset=utf-8
date: Sun, 09 Oct 2022 22:18:31 GMT
set-cookie: vapor-session=ReDSKZniIFtUqq0kThCkLbBe7vBoCpzpCUWqooA6xYQ=; Max-Age=31536000; Path=/; Secure; SameSite=Lax
Vary: Accept-Encoding
REQUEST HEADER:
Accept: application/json, text/plain, */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-GB,en-US;q=0.9,en;q=0.8
Connection: keep-alive
Host: localhost:3000
Referer: http://127.0.0.1:3000/
sec-ch-ua: "Chromium";v="106", "Google Chrome";v="106", "Not;A=Brand";v="99"
sec-ch-ua-mobile: ?0
sec-ch-ua-platform: "macOS"
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36
The reason why I am asking is, that in dev environment cookie will not be stored if it happens.

How http request with "Sec-Fetch-Mode: no-cors" in Blazor Webassembly

How is it possible to make a request by HttpClient with the HTTP request header Sec-Fetch-Mode: no-cors in Blazor Webassembly?
My actuel code is :
var hc = new HttpClient();
var responseHTTP = await hc.GetAsync("https://www.somedomain.com/api/");
But this produces the following HTTP request headers :
:authority: www.somedomain.com
:method: GET
:path: /api/json?input=test&key=AIzaSyDqWvsxxxxxxxxxxxxxxxxx1R7x2qoSkc&sessiontoken=136db14b-88bd-4730-a0b2-9b6c1861d9c7
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9
origin: http://localhost:5000
referer: http://localhost:5000/places
sec-fetch-dest: empty
sec-fetch-mode: cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.116 Safari/537.36
x-client-data: CJS2yQxxxxxxxxxxxxxxxxxxxxxxxxygEI7bXKAQiOusoBCObGygE=
To specifically answer your question, you need to create a HttpRequestMessage first.
e.g.
var request = new HttpRequestMessage(HttpMethod.Get, "https://www.somedomain.com/api/");
request.SetBrowserRequestMode(BrowserRequestMode.NoCors);
request.SetBrowserRequestCache(BrowserRequestCache.NoStore); //optional
using (var httpClient = new HttpClient())
{
var response = await httpClient.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
}
This will correctly set the sec-fetch-mode header to no-cors
I've found however, that the response comes back as empty even though upon inspection in fiddler the response is there.
The closest I got to understanding the problem is through this issue here but unfortunately the bug was closed.

Arduino IDE/ESP8266: Why does a button have to be pressed twice to get the correct output?

I have been teaching myself about programming the ESP8226, specifically the ESP8226-12F. I have this script based on an online example:
#include <ESP8266WiFi.h>
WiFiServer server(80); //Initialize the server on Port 80
void setup() {
WiFi.mode(WIFI_AP); //Our ESP8266-12E is an AccessPoint
WiFi.begin("***","***"); // Provide the (SSID, password);
Serial.begin(115200); //Start communication between the ESP8266-12E and the monitor window
IPAddress HTTPS_ServerIP= WiFi.localIP(); // Obtain the IP of the Server
Serial.print("Server IP is: "); // Print the IP to the monitor window
Serial.println(HTTPS_ServerIP);
while(WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(WiFi.localIP());
server.begin(); // Start the HTTP Server
}
void loop() {
String status;
WiFiClient client = server.available();
if (!client) {
return;
}
Serial.println("Somebody has connected :)");
//Read what the browser has sent into a String class and print the request to the monitor
String request = client.readString();
Serial.println(request);
// Handle the Request
if (request.indexOf("/CLOSE") != -1) {
Serial.println(request.indexOf("/CLOSE"));
status = "CLOSED";
}
if (request.indexOf("/OPEN") != -1) {
Serial.println(request.indexOf("/OPEN"));
status = "OPEN";
}
Serial.println(status);
// The HTML
String s = "HTTP/1.1 200 OK";
s += "Content-Type: text/html\r\n\r\n";
s += "<!DOCTYPE html><html><head><meta http-equiv=\"Content-Security-Policy\" content=\"default-src 'self'\"> <meta name=\"referrer\" content=\"no-referrer\" /></head><body>";
s += "<br><input type=\"button\" name=\"b1\" value=\"OPEN DOOR\" onclick=\"javascript:location.href='/OPEN'\">";
s += "<br><input type=\"button\" name=\"b2\" value=\"CLOSE DOOR\" onclick=\"javascript:location.href='/CLOSE'\">";
if(status == "OPEN") {
s+= "<br><br><p>OPEN</p>";
} else {
s+= "<br><br><p>CLOSED</p>";
}
s += "</body></html>\n";
client.flush(); //clear previous info in the stream
client.print(s); // Send the response to the client
delay(1);
Serial.println("Client disonnected");
You'll see that the initial HTTP response creates two buttons: OPEN DOOR and CLOSE DOOR.
The issue I am having is that the CLOSE button has to be pressed twice in order for the sketch to output "CLOSED".
Here's the output from the Serial Monitor.
1: First time browse to http://10.0.1.92:
Somebody has connected :)
GET / HTTP/1.1
Host: 10.0.1.92
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:5.0.1) Gecko/20100101 Firefox/5.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Client disonnected
2: Press Open Button http://10.0.1.92/OPEN and "OPEN" is displayed
Somebody has connected :)
GET /OPEN HTTP/1.1
Host: 10.0.1.92
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:5.0.1) Gecko/20100101 Firefox/5.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://10.0.1.92/
4 // This is value of request.indexOf("/CLOSE")
OPEN
Client disonnected
3: Press CLOSE http://10.0.1.92/CLOSE and "OPEN" is still displayed
Somebody has connected :)
GET /CLOSE HTTP/1.1
Host: 10.0.1.92
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:5.0.1) Gecko/20100101 Firefox/5.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://10.0.1.92/OPEN
4
371 // No idea where this comes from
OPEN
Client disonnected
4: Press CLOSE the second time and "CLOSED" is displayed:
Somebody has connected :)
GET /CLOSE HTTP/1.1
Host: 10.0.1.92
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:5.0.1) Gecko/20100101 Firefox/5.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Connection: keep-alive
Referer: http://10.0.1.92/CLOSE
4
CLOSED
Client disonnected
Why does the CLOSE button have to be pressed twice to get "CLOSED" to display? Is this a logic issue, or an HTTP issue, or some combination of the two?
This is suspicious:
if(status == "OPEN"){
s+= "<br><br><p>"+status+"</p>";
} else {
s+= "<br><br><p>"+status+"</p>";
}
What's the if statement for if both alternatives are the same?
Also Referer shows three different values when, based on your design, one would expect two. I wonder where you are initially setting the state of this binary state machine?
EDIT:
So OP has updated source code.
if(status == "OPEN") {
s+= "<br><br><p>OPEN</p>";
} else {
s+= "<br><br><p>CLOSED</p>";
}
Versus:
if (request.indexOf("/CLOSE") != -1) {
Serial.println(request.indexOf("/CLOSE"));
status = "CLOSED";
}
if (request.indexOf("/OPEN") != -1) {
Serial.println(request.indexOf("/OPEN"));
status = "OPEN";
}
Do you see how those are logically different now?
This probably means that when the state machine starts, since it's not open, it is CLOSED in the top block but not CLOSED in the bottom. Next button press changes it to open, and then the second changes it to closed? Could this be what's happening?
The problem was these statements:
if (request.indexOf("/CLOSE") != -1){ . . .
if (request.indexOf("/OPEN") != -1){ . . .
If you look at the the response strings you can see that those if statements were matching the GET /OPEN or GET /CLOSED AND the Referer: http://10.0.1.92/CLOSE and Referer: http://10.0.1.92/OPEN.
That 371 I didn't understand at first was the string position of the /OPEN in Referer: http://10.0.1.92/OPEN. That match was flipping status back to OPEN until the Referer changed and producing the observed behavior.
I changed the if statements to include a space so that there would only be a match for the GET /CLOSE or GET /OPEN, i.e.
if (request.indexOf(" /CLOSE") != -1){ . . .
if (request.indexOf(" /OPEN") != -1){ . . .
and it works as it should. So, there was nothing wrong with the logic, it was doing exactly what it should have done ;).
Thanks to JLH for his or her help.

How to get http headers on a service in Jolie Programming Language

I have a service written in Jolie, where I want to extract the http headers on request. In the same way the request.id can be printed out, I would like to print the headers. There is a try on the bold letter down in the code. Here the code:
execution { concurrent }
inputPort UserDB_Service {
Location: "socket://localhost:8002/"
Protocol: http { .format = "json"}
Interfaces: Users, ShutdownInterface, ConnectionPool
}
outputPort DB_Connector {
Location: "socket://localhost:1000/"
Protocol: sodep
Interfaces: ConnectionPool
}
init
{
connectionConfigInfo#DB_Connector()(connectionInfo);
connect#Database(connectionInfo)()
}
main
{
//Example: http://localhost:8002/retrieve?id=1
[ retrieve(request)(response) {
query#Database(
"select * from users where user_id=:id" {
.id = request.id
}
)(sqlResponse);
println#Console( "You have requested the user_id: " + request.id)();
**println#Console( "Request Headers: " + response.format)();**
if (#sqlResponse.row == 1) {
response -> sqlResponse.row[0]
}
} ]
}
Thanks for the help.
I did not understand if you know which headers you want to have in the inbound request or if you just want to print the whole http message for debugging purposes. It is quick in both cases, I report both solutions :)
In the first case you can set the headers parameter of the http protocol for the inputPort to include in the request message also the content of a specific header, e.g.,
http {
.headers.format = "format";
}
and then you can inspect the value in the usual way
println#Console( request.format )()
In the second case, you can use
http {
.debug = true;
.debug.showContent = true
}
to see the log of all http requests and responses and their bodies.
These and further info on protocols and in particular the http protocol is in the documentation of the Jolie site.
I put the output here again. I wonder if it is possible to extract the "iv-user: g47257" header, which I have injected by using Fiddler. Thanks again for the help.
The headers are like this (better format).
INFO: [UserDB_crud.ol] [HTTP debug] Receiving:
HTTP Code: 0
Resource: /retrieve?id=1
--> Header properties
iv-user: g47257
accept-language: en-US,en;q=0.8,da;q=0.6,es;q=0.4
host: localhost:8002
upgrade-insecure-requests: 1
connection: keep-alive
cache-control: max-age=0
accept-encoding: gzip, deflate, sdch
accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp
,*/*;q=0.8
user-agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTM
L, like Gecko) Chrome/48.0.2564.116 Safari/537.36
You have requested the user_id: 1
mar. 10, 2016 2:30:44 PM jolie.Interpreter logInfo
INFO: [UserDB_crud.ol] [HTTP debug] Sending:
HTTP/1.1 200 OK
Server: Jolie
X-Jolie-MessageID: 0
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Content-Length: 72
?V*H,..?/JQ?R*I-.Q?Q*-N-??♦
↑?(?%?"dRs‼3s?\►?????T♂ %??WE
mar. 10, 2016 2:30:44 PM jolie.Interpreter logInfo
INFO: [UserDB_crud.ol] [HTTP debug] Receiving:
HTTP Code: 0
Resource: /favicon.ico
--> Header properties
iv-user: g47257
referer: http://localhost:8002/retrieve?id=1
accept-language: en-US,en;q=0.8,da;q=0.6,es;q=0.4
host: localhost:8002
connection: keep-alive
cache-control: no-cache
pragma: no-cache
accept-encoding: gzip, deflate, sdch
user-agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTM
L, like Gecko) Chrome/48.0.2564.116 Safari/537.36
accept: */*
mar. 10, 2016 2:30:44 PM jolie.Interpreter logWarning
WARNING: [UserDB_crud.ol] Received a message for operation favicon.ico, not specified in the input port at the receiving service. Sending IOException to the caller.
mar. 10, 2016 2:30:44 PM jolie.Interpreter logInfo
INFO: [UserDB_crud.ol] [HTTP debug] Sending:
HTTP/1.1 200 OK
Server: Jolie
X-Jolie-MessageID: 0
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Content-Length: 102
?VJ-*?/R??V?M-.NLOU?R??w?HN-(???S?QJ?O☺?→←↓↑↑?(?$?$???%?d?(?↨?▬%?¶Z)?%?e&???☺ ??Z ?yd?Y
I re-post my last comment here since other people faced the same difficulties found by Efrin but might miss the solution I posted as a comment.
You can inspect the headers of a HTTP request as shown in the code below
include "console.iol"
inputPort Me {
Location: "socket://localhost:8000"
Protocol: http { .headers.iv_user = "ivUser" }
RequestResponse: myRequest
}
main {
myRequest( request )(){ println#Console( request.ivUser )() }
}
Remember that, as reported in the documentation, Jolie http.headers parameters map - in header names with _, e.g., in your case, header iv-user becomes iv_user in the Jolie HTTP protocol parameters.
Besides the description and code found in the Jolie documentation, you can find further examples and a more thorough explanation on how the HTTP protocol works in Jolie in its presentation paper wrote by Montesi https://doi.org/10.1016/j.scico.2016.05.002.

POST raw to server Processing

I have an Intel Edison running a Node.JS server that is printing everything I post to it into the console. I can successfully post to it using Postman and see the sent raw data in the console.
Now I'm using Processing to POST to it, which will fire off different events on the Node.JS server.
My problem is that I can't seem to successfully POST the raw body to the server, I've been trying to get this working for several hours already.
import processing.net.*;
String url = "192.168.0.107:3000";
Client myClient;
void setup(){
myClient = new Client(this, "192.168.0.107", 3000);
myClient.write("POST / HTTP/1.1\n");
myClient.write("Cache-Control: no-cache\n");
myClient.write("Content-Type: text/plain\n");
//Attempting to write the raw post body
myClient.write("test");
//2 newlines tells the server that we're done sending
myClient.write("\n\n");
}
The console shows that the server received the POST, and the correct headers, but it doesn't show any data in it.
How do I specify the that "test" is the raw POST data?
The HTTP code from Postman:
POST HTTP/1.1
Host: 192.168.0.107:3000
Content-Type: text/plain
Cache-Control: no-cache
Postman-Token: 6cab79ad-b43b-b4d3-963f-fad11523ec0b
test
The server output from a POST from Postman:
{ host: '192.168.0.107:3000',
connection: 'keep-alive',
'content-length': '4',
'cache-control': 'no-cache',
origin: 'chrome-extension://fhbjgbiflinjbdggehcddcbncdddomop',
'content-type': 'text/plain',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.111 Safari/537.36',
'postman-token': 'd17676a6-98f4-917c-955c-7d8ef01bb024',
accept: '*/*',
'accept-encoding': 'gzip, deflate',
'accept-language': 'en-US,en;q=0.8' }
test
The server output from my POST from Processing:
{ host: '192.168.0.107:3000',
'cache-control': 'no-cache',
'content-type': 'text/plain' }
{}
I just figured out what was wrong, I needed to add the content-length header to tell the server how much data to listen for, and then a newline before the data.
Final code:
import processing.net.*;
String url = "192.168.0.107:3000";
Client myClient;
void setup(){
myClient = new Client(this, "192.168.0.107", 3000);
myClient.write("POST / HTTP/1.1\n");
myClient.write("Cache-Control: no-cache\n");
myClient.write("Content-Type: text/plain\n");
myClient.write("content-length: 4\n");
myClient.write("\n");
myClient.write("test");
myClient.write("\n\n");
}

Resources