Question about accessing data from REST-ful resource using c++ and poco - c++

I have succesfully retrieved the data using a java HttpURLConnection and setting request method as "GET". I would like to implement this in c++ as well (I'm using poco). The URL I am trying to access is "https://open.faceit.com/data/v4".
When I send the request I get a status code 400 (Bad Request) and the response message "400 The plain HTTP request was sent to HTTPS port". Why would using HTTP in java work, but using POCO in c++ I get this error? Should I be using HTTPSClientSession instead, and if so why was I able to use HTTP in java?
java code that gives return code 200
URL url = new URL(dataURL);
HttpURLConnection hc = (HttpURLConnection) url.openConnection();
hc.setRequestMethod("GET");
hc.setRequestProperty("Authorization", "Bearer " + code);
hc.setDoOutput(true);
int rCode = hc.getResponseCode();
c++ thats giving me return 400
Poco::URI uri("https://open.faceit.com/data/v4/players?nickname=FadesfasT&game=CSGO");
std::string path(uri.getPathAndQuery());
HTTPClientSession session(uri.getHost(), uri.getPort());
HTTPRequest request(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
request.add("Authorization", "Bearer" + token);
request.setContentType("application/json");
session.sendRequest(request);
HTTPResponse response;
std::istream& in_stream = session.receiveResponse(response);
std::ostringstream out_stream;
Poco::StreamCopier::copyStream(in_stream, out_stream);
std::cout << out_stream.str() << std::endl;

The problem with your C++ snippet is that you are mixing an URL containing a HTTPS address with a request targeting HTTP.
My uneducated guess about why the issue does not appear in Java is that it recognizes the 'https' in the address and automatically uses an appropriate handler for that. Fact is, in C++ or at least in POCO you have to pick the appropriate request yourself.
Basically you have 3 options:
Use a HTTP URL with the HTTP request that you have already written.This does not really seem to be an option, because your URL redirects HTTP to HTTPS so this would not work.
Use a HTTPS URL and change your request to HTTPS. It might be more difficult than option 1, but not that hard and there exists a SO question discussing this. To summarize:
Should I be using HTTPSClientSession instead [...] ?
Yes, if you decide to go with this option
Use a library other than POCO, which seems to be the solution in your case as mentioned in the comments. I for example know of CURL and libhttp, which imo are at least as easy to use as POCO, if not easier. The links lead to pages containing examples on how to execute HTTPS requests.

Related

grpc metadata not showing in http header

I am trying to send a grpc request from a c++ client to a server. On the way the http passes through a proxy that checks http header fields. I wanted to add a custom field version to be checked by that proxy.
I am adding it to the grpc context and sending the request:
protos::MyProtoRequest req;
protos::MyProtoResponse res;
grpc::ClientContext context;
context.AddMetadata("version", "0.1.2");
// proto_stub is a protobuf stub interface
const grpc::Status status = proto_stub->MyOperation(&context, req, &res);
Then inside my proxy I inspect the http header and I do not see a version field in it.
I once did something similar but with the name authorization instead of version and it worked. Here I am doing the same thing with another name and it fails. I am confused. What am I doing wrong?
Thank you

How to request with request header to https URL using C++ REST SDK?

I'm trying to make source that requests to specific https URL with request header using c++ rest sdk.
ex)https://111.0.0.1:1111/vl/api/auth
Then, I want to allocate response value to char* value and print.
It is first time to use rest sdk. So I searched many things.
But,there are no solutions request 'Get' with request header
RequestHeader is like this :
id:"1234567890"
auth:"7d8ffbecb05d59459f96d6e3aac8542e"
But I don't know what to do
httpclient client(U("http://localhost:9991/test"));
////then How???
I need your help!
all you need to do like
http_request request(methods::GET);
request.headers().add(L"id", L"1234567890");
request.headers().add(L"auth", L"7d8ffbecb05d59459f96d6e3aac8542e");

Can ZOHO deluge script getUrl() function read HTTP response headers?

When trying to use getUrl() to grab a CSV file from a URL with basic .htaccess authorization, I am redirected to an Amazon S3 location. The getURL() function passes the original HTTP headers (for the auth) to Amazon S3 which Amazon thinks is an Amazon token; this causes the following error in the response:
Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified
I can't see these issues talked about anywhere other than an advisory from Thompson Reuters: https://community.developers.thomsonreuters.com/questions/29247/aws-download-x-direct-download-returns-invalid-arg.html
The fix is to receive the redirect back from the remote server, look at the response and pull out the new (redirected) URL and grab the CSV file from there without the auth details in the header.
Is there a way in deluge script ZOHO to do this? The getUrl() function seems really basic and the documentation is very thin.
The other way to do this is a 'middleware' application that can use CURL, save the CSV's on a remote server then use ZOHO getUrl() to pull these CSV files. This is not an optimal solution but unless ZOHO gives access to some HTTP client functions then I don't see another way.
To get the detail of the response headers include detailed:true in the invokeurl request.
Example:
// parameters is a Map
// header is a Map
response = invokeurl
[
url :url
type :POST
parameters:parameters
headers:header
detailed:true
];
// To see all headers and content
info response;
// To see the http response code
info response.get('responseCode');
// With detailed:true any html or json returned will be put in responseText
// info response.get('responseText');
// To see the all http response headers
info response.get('responseHeader');
// To see a specific http response header
// Note: case matters in the response headers name
// "Content-Type" won't find "content-type"
info response.get('responseHeader').get('content-type');
// was the url redirected to another url?
info response.get('responseHeader').get('location');
// get the redirect url
redirect_url = response.get('responseHeader').get('location')
from there you can process the redirect url and pass it to the next http request.
Recommendation:
After working for months both including detailed:true and not including it, I now lean toward always including it. detailed:true includes more useful information and has a helpful regular structure: {responseCode: <code>, responseHeaders: <headers>, responseText: <returned-data>}.
This is possible in Deluge using the invoke URL task - https://www.zoho.com/deluge/help/web-data/invokeurl-task.html#response.
invokeURL can hand over the response headers to you from which you can get the redirect URL and then proceed with the authentication.

HTTP error code: 302 when calling https webservice

I am trying to call a SOAP RPC style web service and getting the following error:
Exception in thread "main" com.sun.xml.internal.ws.client.ClientTransportException: The server sent HTTP status code 302:
This is a https web service and I have imported the certificate into cacerts thru browser but getting same result. Please note that, I can consume a REST webservice from the same machine without importing the certificate.
What I am missing when calling a SOAP service? Is it my client issue or something need to be done on the server side. I have access to the server.
HTTP status code 302 is a redirect, and so is unlikely due to a certificate problem. My initial guess is that you need to add a / (or remove it) from your URL. Some http server frameworks will redirect when a resource does not end in a /, so, instead of:
GET /myRpcEndpoint
Try
GET /myRpcEndpoint/
The other possibility is that this resource requires authentication and the server is redirecting you to a login page. If you want to know what is going on (and not guess), take a look a the the response headers for the 302. There will be a Location header telling you where the server wants you to go instead.
Had a similar issue where client code would receive a HTTP 302 error code when communicating with https and would work fine when communicating with http. In client code,you might need to specify the endpoint address on the request context using the BindingProvider.ENDPOINT_ADDRESS_PROPERTY property. Following the JAX-WS paradigm, the example below should work.
Please note that only the BindingProvider.ENDPOINT_ADDRESS_PROPERTY needs to be defined, the rest of your code should remain the same.
public static void main(String args[]) throws {
ObjectFactory factory = new ObjectFactory();
GetProducts_Service service = new GetProducts_Service();
GetProducts getProducts = service.getGetProductsPort();
final BindingProvider getProductsBP = (BindingProvider) getProducts;
getProductsBP.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"https://example.server.net/ExampleServicesWar/GetProducts");
GetProductsRequest request = factory.createGetProductsRequest();
GetProductsResponse response=getProducts.getProducts(request);
List<Product> products=response.getProducts();
}
All you have to is to use correct end point url
((BindingProvider)port).getRequestContext().put(BindingProvider.
ENDPOINT_ADDRESS_PROPERTY, "https://yourservice");
Need to import at the top:
import javax.xml.ws.BindingProvider;
port is Method call:
full source:
private static String getApplicationStatus(java.lang.String remoteAccessKey, java.lang.Integer responseId) {
net.quotit.oes._2010.ws.applicationstatusupdate.OASStatusUpdateService service = new net.quotit.oes._2010.ws.applicationstatusupdate.OASStatusUpdateService();
net.quotit.oes._2010.ws.applicationstatusupdate.IApplicationStatusUpdate port = service.getStatusUpdate();
((BindingProvider)port).getRequestContext().put(BindingProvider.
ENDPOINT_ADDRESS_PROPERTY, "https://servicename/basic");
return port.getApplicationStatus(remoteAccessKey, responseId);
}

Proxy Authentication in POCO Net C++ library

I have been playing with the Poco Net library for some time, it is quite nice. Very convenient and easy to understand.
I was able to set a proxy address, and it is saying 407 Proxy authorization required, properly. I figured that
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
req.setCredentials(scheme, authInfo);
I tried values like "basic", "plaintext" in scheme, and "user:password" in authInfo. It doesn't seem to work. Google isn't helping.
Has anyone done this using Poco Net before? Or is the usage obvious and I'm not able to get it to work because of my ignorance towards proxy authentication in general? Please advice.
EDIT: After some more playing around, I think the setCredentials function is used when the remote server is expecting authentication information to login. I have not been able to find a way to do proxy authentication using Poco Net libraries. I was able to set the proxy server and port though. This is what I would have if there was just a proxy server without authentication:
HTTPClientSession session(uri.getHost(), uri.getPort());
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
session.setProxy("host", port);
session.sendRequest(req);
Need help.
EDIT: Based on the solution suggested by #StackedCrooked, I tried setting proxy authentication details to the request header before making the request, and in another approach found on the internet, I set proxy auth details only after making an initial request and a 407 error comes, and then making the request again. Both methods kept on giving the same 407 error. My current code looks like this:
HTTPClientSession session(uri.getHost(), uri.getPort());
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
session.setProxy("10.7.128.1", 8080);
req.set("Proxy-Authentication", "Basic bGVlbGE6bGVlbGExMjM=");
session.sendRequest(req);
You probably need to add the Proxy Authorization field to the HTTP headers. Poco's HTTPRequest class doesn't have a dedicated method for this. However, since it inherits the NameValueCollection class publicly you can set it like this:
req.set("Proxy-Authorization" , "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
Where QWxhZGRpbjpvcGVuIHNlc2FtZQ== is the base64 encoded version of "Aladdin:open sesame".
A lot of these problems become easier once you learn a little about the HTTP protocol. I am now mostly preaching to myself :)
I haven't used this myself, but have you looked at the HTTPBasicCredentials class? It wraps up the call to req.setCredentials via its authenticate method. You would end up with something along the lines of:
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
HTTPBasicCredentials cred("user", "password");
cred.authenticate(req);