Setting a cookie using JavaFX's WebEngine/WebView - cookies

I cannot seem to find any way to set a cookie programatically using WebEngine / WebView in JavaFX. The API doesn't give any idea as to how to obtain an HttpRequest-like object to modify the headers (which is what I use in the app for XML-RPC), or any sort of cookie manager.
No questions on this page seem to touch on the issue either - there is this but it just disables cookies when in applet to fix a bug, my app is on desktop btw.
The only way I image I could do it is by requesting the first page (which requires a cookie with a sessionID to load properly), getting an "access denied"-style message, executing some javascript in the page context which sets the cookie and then refreshing. This solution would be a horrible user experience though.
How do I set a cookie using WebEngine?
Update: Taking a clue from a question linked above, I tried digging around for some examples of using CookieManager and related APIs. I found this code, which I then tried to incorporate into my app, with weird results;
MyCookieStore cookie_store = new MyCookieStore();
CookieManager cookie_manager = new CookieManager(cookie_store, new MyCookiePolicy());
CookieHandler.setDefault(cookie_manager);
WebView wv = new WebView();
Now lets say we do this:
String url = "http://www.google.com/";
wv.getEngine.go(url);
Debugging in Eclipse after this request has been made shows that the cookie store map holds a cookie:
{http://www.google.com/=[NID=67=XWOQNK5VeRGEIEovNQhKsQZ5-laDaFXkzHci_uEI_UrFFkq_1d6kC-4Xg7SLSB8ZZVDjTUqJC_ot8vaVfX4ZllJ2SHEYaPnXmbq8NZVotgoQ372eU8NCIa_7X7uGl8GS, PREF=ID=6505d5000db18c8c:FF=0:TM=1358526181:LM=1358526181:S=Nzb5yzBzXiKPLk48]}
THAT IS AWESOME
WebEngine simply uses the underlying registered cookie engine! But wait, is it really? Lets try adding a cookie, prior to making the request...
cookie_store.add(new URL(url).toURI(), new HttpCookie("testCookieKey", "testCookieValue"));
Then I look at the request in Wireshark...
GET / HTTP/1.1
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/535.14 (KHTML, like Gecko) JavaFX/2.2 Safari/535.14
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Cache-Control: no-cache
Pragma: no-cache
Host: www.google.com
Connection: keep-alive
No cookie for me :(
What am I doing wrong?

I have managed to solve this issue with the help of Vasiliy Baranov from Oracle. Vasiliy wrote to me:
Try putting the cookie into java.net.CookieHandler.getDefault() after
the WebView is instantiated for the first time and before the call to
WebEngine.load, e.g. as follows:
WebView webView = new WebView();
URI uri = URI.create("http://mysite.com");
Map<String, List<String>> headers = new LinkedHashMap<String, List<String>>();
headers.put("Set-Cookie", Arrays.asList("name=value"));
java.net.CookieHandler.getDefault().put(uri, headers);
webView.getEngine().load("http://mysite.com");
This will place the cookie into the store permanently, it should be sent out on every subsequent request (presumably provided that the server doesn't unset it).
Vasiliy also explained that WebView will install it's own implementation of the CookieHandler, while retaining cookies put into the default one.
Lastly, he mentions something quite intriguing:
Do not waste your time trying to use java.net.CookieManager, and
java.net.CookieStore. They are likely to cause problems with many
sites because they implement the wrong standard.
I tried googling after this but it doesn't seem to be common knowledge. If anyone is able to provide more details I would be grateful. It seems weird, since it seems CookieStore and CookieManager are used by a lot of software out there.

Solution for java.net.CookieManager
Cookies serialization:
List<HttpCookie> httpCookies = cookieManager.getCookieStore().getCookies();
Gson gson = new GsonBuilder().create();
String jsonCookie = gson.toJson(httpCookies);
Cookies deserialization:
Gson gson = new GsonBuilder().create();
List<HttpCookie> httpCookies = new ArrayList<>();
Type type = new TypeToken<List<HttpCookie>>() {}.getType();
httpCookies = gson.fromJson(json, type); // convert json string to list
for (HttpCookie cookie : httpCookies) {
cookieManager.getCookieStore().add(URI.create(cookie.getDomain()), cookie);
}

Related

upload data with HTTP method POST or PUT

I'm working with STM32-microcontroller and C-languege and want to send to and receive the data from my website. I can receive the .txt file with the "GET" method from website via this code:
static const char http_request[] = "GET "WEBSITE_SUB_ADDRESS" HTTP/1.1\r\nHost: "WEBSITE_ADDRESS"\r\n\r\n";
net_sock_send(socket, (uint8_t *) http_request, len);
net_sock_recv(socket, (uint8_t *) buffer + read, NET_BUF_SIZE - read);
Now I want to send or upload the data to the website in a file with http-method (POST or PUT, ...). How can I do it?
You first need to decide if you want to use POST or PUT.
The PUT method completely replaces whatever currently exists at the target URL with something else. With this method, you can create a new resource or overwrite an existing one given you know the exact Request-URI. ...In short, the PUT method is used to create or overwrite a resource at a particular URL that is known by the client.
The HTTP POST method is used to send user-generated data to the web server. For example, a POST method is used when a user comments on a forum or if they upload a profile picture. A POST method should also be used if you do not know the specific URL of where your newly created resource should reside. ...In short, the POST method should be used to create a subordinate (or child) of the resource identified by the Request-URI.
from https://www.keycdn.com/support/put-vs-post
While connected to the server you would send a HTTP header just as you have done with the GET request that would look somthing like this:
POST /test HTTP/1.1\r\n
Host: www.myServer.com\r\n
Content-Type: text/plain\r\n
Content-Lenght: 8\r\n
Accept: */*\r\n
\r\n
someData
You might also want to check if the server recived the message by looking at the header that is sent back to you, it should include HTTP/1.1 200 OK.
Edit: to get it into a file try /test/mytext.txt but i dont have a way of testing if this works
A good place to test the request is Post Test Server V2. hope this helps
#Flynn Harrison
I tested your method as follows:
static const char http_request[] = "POST "SUB_ADDRESS" HTTP/1.1\r\n"
"Host: "HOST_ADDRESS"\r\n\r\n"
"Content-Type: text/plain\r\n"
"Content-Lenght: 13\r\n"
"Accept: */*\r\n"
"\r\n"
"Data for Write Test";
and then:
net_sock_setopt(socket, "tls_server_name", (uint8_t*)HOST_ADDRESS, sizeof(HOST_ADDRESS));
net_sock_open(socket, HOST_ADDRESS, TIME_SOURCE_HTTP_PORT, 0);
net_sock_send(socket, (uint8_t *) http_request, len);
net_sock_recv(socket, (uint8_t *) buffer + read, NET_BUF_SIZE - read);
When I tried "/test.txt" at SUB_ADDRESS, I get the HTTP / 1.1 200 OK message but immediately after receiving the file contents, in the same buffer, I receive the HTTP / 1.1 400 Bad Request message and I do not see any changes to the file. My response from server is as follows:
HTTP/1.1 200 OK
.
.
.
This is a Test.... (Text-File Content)
HTTP/1.1 400 Bad Request\r\nDate: Fri, 09 Aug 2019 09:03:56
.
.
.
In the site you mentioned, the POST method works well but its mechanism is not clear which I can use. I tried to test the POST method with this site and my device but got error "411 Length Required".

Hi How to handle 302 response in dp:url-open()

Hi How to handle 302 response in dp:url-open(), and how to deleate all the request http headers before sending to back-end. those headers are dynamic.
Thanks,
Manoj.
For(hypothetically) a Multi-Protocol Gateway, go in the "advanced" tab, switch the "Follow Redirects" option off. Then the 302 http response is treated just as any 2xx responses.
From that point on, you can create a GatewayScript code that test the error code (and if value == 302), then delete all headers.
The code would look something like this (please correct if I missed something):
var hm = require('header-metadata');
var all_Headers = hm.current.headers;
console.error(all_Headers);
if (hm.current.statusCode == 302) {
for (var headerName in all_Headers) {
hm.current.remove(headerName);
}
}
Here are some good references for GatewayScript:
Nice IBM "playground" site, click on "samples" for the cool part
Official GatewayScript code documentation
Specific part about header deleting in GatewayScript
I partially based my example on this healthcheck example

How to include Zumo API version header in rest client

I have an Azure Mobile App backend working web service. I am trying to carry out basic crud operations. I understand that you can use a url like myapp/tables/object?zumo-api-version=2.0.0 and this works fine when I am getting data. However, when I want to put, delete etc it requires an id. If I type myapp/tables/object/dsjkfhsdjkfjsdfjkkdjf?zumo-api-version=2.0.0 for example where the string is the id I can carry out the operation. Similarly, if I enter an id in Swagger, I can also carry out the put operation. However, I am unsure as to how to go about adding the zumo-api-version details on the client side. How can I include the zumo version header in my project?
See Header Specification here:
https://azure.microsoft.com/en-us/documentation/articles/app-service-mobile-client-and-server-versioning/
The key ZUMO-API-VERSION may be specified in either the HTTP header or the query string. The value is a version string in the form x.y.z.
For example:
GET https://service.azurewebsites.net/tables/TodoItem
HEADERS: ZUMO-API-VERSION: 2.0.0
POST https://service.azurewebsites.net/tables/TodoItem?ZUMO-API-VERSION=2.0.0
So you could do:
$ curl -sv -H "ZUMO-API-VERSION: 2.0.0" \
http://{mobileapp}.azurewebsites.net/tables/todoitem
> GET /tables/todoitem HTTP/1.1
> Host: {mobileapp}.azurewebsites.net
> User-Agent: curl/7.49.1
> Accept: */*
> ZUMO-API-VERSION: 2.0.0
>
< HTTP/1.1 200 OK
[...]
[{
"id":"40b996d6-ec7f-4188-a310-0f02808e7093",
"createdAt":"2016-08-31T11:30:11.955Z",
"updatedAt":"2016-08-31T11:30:11.971Z",
"version":"AAAAAAAAG5s=",
"deleted":false,
"Yo_mobileapp":"Sup"
}]
Note ZUMO-API-VERSION: 2.0.0 passed in as Header.
If you're asking "Which is better?", there's no better. They do the same thing. That being said, it's probably easier and cleaner to send a Header for most use cases.

Response.Cookies collection seems corrupted and causes error

After many hours of debugging some strange error occurring on our classic asp website, I found what could be the cause of the error when reading the Request.Cookies collection.
An example of HTTP_COOKIE header received from the client browser is:
HTTP_COOKIE:=true; ASPSESSIONIDSQRRDDRS=PAMMOMMAKGDHMAOGLEJPMLIM; X-XAct-ID=e8eb8d86-670c-46ef-ba64-14cc931fd13f; 643af15a72242b4dd892fe8c0c088a39=d60badbf9bebc14f573b4aa7f0474deb; sid=fr33cf49981a883ca433dd333692832ffdd8ee8a; _locale=pt_BR; 21411886ec077054c92080ba94ba91a2=fac31597bd8bf7e4cb5991c7547ad58c; brstyleid=9; brsessionhash=9d5dce337d314e85ec44a9b69a258fbd; brlastvisit=1438799253; brlastactivity=0; lnlang=no; _talentoday_session=3e9172578651a5bd36a9687bfadf7ada; sticky=no-match; BBC-UID=f5f51c92557579d5f8b9575621a86a8a48e81e9c3020707c72e9631f89622caf0Mozilla%2f5%2e0%20%28Macintosh%3b%20Intel%20Mac%20OS%20X%2010%2e8%3b%20rv%3a21%2e0%29%20Gecko%2f20100101%20Firefox%2f21%2e0; ypsession=a%3A5%3A%7Bs%3A10%3A%22session_id%22%3Bs%3A32%3A%22f90505e4298571bc306b4845413b42b2%22%3Bs%3A10%3A%22ip_address%22%3Bs%3A11%3A%225.9.145.132%22%3Bs%3A10%3A%22user_agent%22%3Bs%3A65%3A%22Mozilla%2F5.0+%28Windows+NT+6.2%3B+rv%3A21.0%29+Gecko%2F20130326+Firefox%2F21.0%22%3Bs%3A13%3A%22last_activity%22%3Bi%3A1438799253%3Bs%3A9%3A%22user_data%22%3Bs%3A0%3A%22%22%3B%7D0214f53a8afe0b556dd83f2b1a3ee88d; yumpu_slc=no; ASPSESSIONIDSQDSCQTS=BLAAJGIAHPOPIFJKJBFGGCOD; ljident=2969834924.20480.0000; ftrlan=en; ismobile=0; geneweb_base=bengos; gntsess5=06cfbqo0i1qgcfecn5f56msfo4; autolang=fr; device_view=full; experiments_groups=51bdba5bd9f6233a5042745665e03d3265a87fac%7Ea%3A1%3A%7Bs%3A6%3A%2278%3A115%22%3Bs%3A8%3A%22archives%22%3B%7D; session=4e62cb6c840cd84689029e488605282970fc2925%7E55c2559636cbe2-35808714; ASP.NET_SessionId=ivmbtcjboba0sft03rrksblk; PD_Captcha=rcount=1&SearchResults=http%3a%2f%2fdoctor.webmd.com%2fdoctor%2fgonzalo-de-quesada-md-537ca80f-752d-4aaa-82c3-1c2c7b447022-appointments; NSC_epdups-xfc.dpo.tfb1*80=ffffffffaf1a188345525d5f4f58455e445a4a423660; SESSION_ZIG=Yzg1NmRjYThkMjE4MWE5OGQ2M2Q3YTU2NzNmOTE0NGE6OjdjZDFkYzZjYTcyMzYxNDRhMTI1YWVkNjM2ZWIxNDUy; GSCK_AVCA=YToxOntpOjcwNzM4O2k6MTQzODc5OTI1NDt9OjpmZWY4MWViYTU5NTJiYzU5MTVlZmVlMTQ4YWY0M2JhNg%3D%3D; _uv_id=1466248598; SERVERID=r88|VcJVm|VcJVm; SESS57cde0ccb3a63ef1692b1270e90b46cc=bctkcqro3j98uvgn84e7h7e5i0; VISITOR_INFO1_LIVE=k__fn-xf0m4; YSC=NKv9iWTX4AQ; s1=6q5M2Ujn7Qdc663oy88WrFn4_wmABvFNB; __cfduid=d7d5f0bf9eb9853a44349aa3aafac5ec51438799254; CAKEPHP=hi2u1sapas3r6n7iuje3nvbg15; visited=20150805; PHPSESSID=vbdub74d1ee6uvs42rlgaejjt3; BX=7sb6jvdas4lcn&b=3&s=fi; NID=70=hRIXSnhVo35s-0cSEvmn7mHoqIgfYGjFsgRMvATllAVMIXg_Q6eZpVITVZDVRmYD5TnbJCm1kBAIk1Hamk1ilSLtekGVSKRr51GZy1_-ul2AK8qXbdUBADsbuFLAC-xX; startD=R3876064936; session_id=7bb23c0df78d28170d038fa36d43f989; cat=198897; cpop=1
First, notice the first cookie is missing its key, is it valid and if not may it explain why I get an error when trying to access Request.Cookies collection ?
Also, except maybe "ASPSESSIONIDXXXXXXXX" cookies, all other cookies are even not belonging to my website domain, what the heck ? "correct" browsers should not send cookies from other domains right ?
This guy user agent string is: Mozilla/5.0 (Macintosh; Intel Mac OS X 107) AppleWebKit/534.48.3 (KHTML like Gecko) Version/5.1 Safari/534.48.3
, i would think Safari would follow this domain rule... anyway it does not seems related to a specific browser because i get many similar request with other browsers...
Any idea what is happening ?
I found with the ip addresses that requests were not legitimate and probably made by a bot which is spoofing user agent string.
And also found that any attempt to read Request.Cookies raise an error when the cookie request header contains a cookie with no key like "=true", it is sad they didn't think of ignoring invalid cookie strings when implementing the collection.

how to parse http request in c++

I'm trying to write a small c++ webserver which handles GET, POST, HEAD requests. My problem is I don't know how to parse the headers, message body, etc. It's listening on the socket, I can even write stuff out to the browser just fine, but I'm curious how should I do this in c++.
Afaik a standard GET/POST request should look something like this:
GET /index HTTP/1.1
Host: 192.168.0.199:80
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.97 Safari/537.22
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
this is the message body
All lines ended with '\r\n'.
Should I just split the request at '\n' and trim them (and if so how)?
Also how to handle files in post data?
Main thing I want to achieve is to get a vector containing headers key=>value pairs, a string with request method, the post data (like in PHP, if it's present), and the query string (/index for example) as string or vector splitted by '/'.
Thanks!
Before doing everything yourself, I introduce you Poco:
class MyHTTPRequestHandler : public HTTPRequestHandler
{
public:
virtual void handleRequest(HTTPServerRequest & request,
HTTPServerResponse & response) {
// Write your HTML response in res object
}
};
class MyRequestHandlerFactory : public HTTPRequestHandlerFactory
{
MyHTTPRequestHandler handler;
public:
MyRequestHandlerFactory(){}
HTTPRequestHandler* createRequestHandler(const HTTPServerRequest& request)
{
const string method = request.getMethod();
if (method == "get" || method == "post")
return &handler;
return 0;
}
};
int main()
{
HTTPServerParams params;
params.setMaxQueued(100);
params.setMaxThreads(16);
ServerSocket svs(80);
MyRequestHandlerFactory factory;
HTTPServer srv(&factory, svs, &params);
srv.start();
while (true)
Thread::sleep(1000);
}
Boost.Asio is a good library but relativel low-level. You’ll really want to use a higher level library. There’s a modern C++ library called node.native which you should check out. A very server can be implemented as follows:
#include <iostream>
#include <native/native.h>
using namespace native::http;
int main() {
http server;
if(!server.listen("0.0.0.0", 8080, [](request& req, response& res) {
res.set_status(200);
res.set_header("Content-Type", "text/plain");
res.end("C++ FTW\n");
})) return 1; // Failed to run server.
std::cout << "Server running at http://0.0.0.0:8080/" << std::endl;
return native::run();
}
It doesn’t get much simpler than this.
Yes, this is basically just string parsing and then the response creating that goes back to the browser, following the specification.
But if this is not just an hobby project and you do not want to take on a really big task you should use either Apache, if you need a web server you need to extend, or tntnet, if you need a c++ web framework, or cpp-netlib if you need C++ network stuff.
You may want to consider Proxygen, Facebook's C++ HTTP framework. It's open source under a BSD license.