Implementing custom HTTP methods with HttpCore - java

I'm new to Java and am hoping for some direction with Apache HttpCore library.
I've written a simple server, and would like to implement a few custom HTTP methods. I've gone through the docs a few time but haven't been able to figure it out.
It looks like the 501 Not Implemented is raised in HttpService.doService(), but overriding that method doesn't work. My request handler doesn't get called.
Any help will be appreciated.
Thanks.
Here's the gist of what I've got:
ServerSocket serverSocket;
HttpParams params;
HttpService httpService;
serverSocket = new ServerSocket(8000);
params = new BasicHttpParams();
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000);
params.setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024);
params.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false);
params.setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true);
params.setParameter(CoreProtocolPNames.ORIGIN_SERVER, "?");
BasicHttpProcessor httpproc = new BasicHttpProcessor();
httpproc.addInterceptor(new ResponseDate());
httpproc.addInterceptor(new ResponseServer());
httpproc.addInterceptor(new ResponseContent());
httpproc.addInterceptor(new ResponseConnControl());
HttpRequestHandlerRegistry registry = new HttpRequestHandlerRegistry();
registry.register("*", new HttpRequestHandler() {
public void handle(HttpRequest request, HttpResponse response,
HttpContext context) throws HttpException, IOException {
System.out.println(request.getRequestLine().toString());
}
});
httpService = new HttpService(httpproc, new DefaultConnectionReuseStrategy(), new DefaultHttpResponseFactory());
httpService.setParams(params);
httpService.setHandlerResolver(registry);
Socket socket = serverSocket.accept();
DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
conn.bind(socket, params);
HttpContext context = new BasicHttpContext();
httpService.handleRequest(conn, context);
socket.close();
conn.shutdown();
serverSocket.close();
Response:
# curl -X FOO -i http://127.0.0.1:8000
HTTP/1.0 501 Not Implemented
Content-Length: 26
Content-Type: text/plain; charset=US-ASCII
Connection: Close
FOO method not supported
Request line isn't written to System.out unless method is GET, POST, etc.
SOLUTION: I needed to implement a HttpRequestFactory.
e.g.:
DefaultHttpServerConnection conn = new DefaultHttpServerConnection() {
#Override
public DefaultHttpRequestFactory createHttpRequestFactory() {
return new DefaultHttpRequestFactory() {
#Override
public HttpRequest newHttpRequest(final RequestLine requestline) {
return new BasicHttpRequest(requestline);
}
#Override
public HttpRequest newHttpRequest(final String method, final String uri) {
return new BasicHttpRequest(method, uri);
}
};
}
};

It doesn't look like you need to override doService(). You rather need to implement a handler for you method and make sure
handler = this.handlerResolver.lookup(requestURI);
returns your handler. I take you did that, but for some reason your handler is not found. I bet you didn't register it properly.

Related

Get java.net.SocketException: java.lang.IllegalStateException: No factory found. While trying to send POST request to HTTP server

I am writing an Android application in Android Studio which is sending a POST request to the server.
I have made a class for the HTTP connection:
public class PostTask extends AsyncTask {
#Override
protected Object doInBackground(Object[] objects) {
Requester requester = new Requester();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("https://dev-api.shping.com/serialization-service/reassignment/task");
HttpResponse response = null;
HttpHost httpproxy = new HttpHost("hmkproxy1.fmlogistic.fr",8080);
httpclient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, httpproxy);
try {
httppost.setHeader("authenticateit_identity_ticket","63eb8926-e661-42c1-998d-3f008665c8e5");
httppost.setHeader("cache-control","no-cache");
httppost.setHeader("content-type", "application/json");
StringEntity params = new StringEntity(requester.getJsonObject().toString());
httppost.setEntity(params);
// Execute HTTP Post Request
response = httpclient.execute(httppost);
System.out.println(response);
} catch (ClientProtocolException e) {
System.out.println("FUCK1");
} catch (IOException e) {
System.out.println(e);
}
return null;
}
}
I am connecting through a proxy. I get this exception while my app works: java.net.SocketException: java.lang.IllegalStateException: No factory found
Please help me, there is nearly no information about this exception on the internet. I tried to add some socket factories to my method, but it doesn't seems to work so I deleted them.
Thanks!
Remove android:networkSecurityConfig from manifest.

Close a socket created in handle of HttpRequestHandler

i'm in mid of implementing a proxy using apache's HttpCore .
This is my HttpRequestHandler it is based on reverse proxy exampleby apache link :
static class ProxyHandler implements HttpRequestHandler {
private final HttpHost target;
private final HttpProcessor httpproc;
private final HttpRequestExecutor httpexecutor;
private final ConnectionReuseStrategy connStrategy;
private SocketFactory sf;
public ProxyHandler(
final HttpHost target,
final HttpProcessor httpproc,
final HttpRequestExecutor httpexecutor,
SocketFactory sf) {
super();
this.target = target;
this.httpproc = httpproc;
this.httpexecutor = httpexecutor;
this.sf = sf;
this.connStrategy = DefaultConnectionReuseStrategy.INSTANCE;
}
public void handle(
final HttpRequest request,
final HttpResponse response,
final HttpContext context) throws HttpException, IOException {
final int bufsize = 8 * 1024;
URI uri = null;
try {
uri = new URI(request.getRequestLine().getUri());
} catch (URISyntaxException e) {
e.printStackTrace();
return;
}
String domain = uri.getHost();
HttpHost host = new HttpHost(domain, 80);
System.out.println("host "+domain);
DefaultBHttpClientConnection outconn = (DefaultBHttpClientConnection) context.getAttribute(HTTP_OUT_CONN);
final Socket outsocket = sf.createSocket(host.getHostName(), this.target.getPort());
outconn = new DefaultBHttpClientConnection(bufsize);
outconn.bind(outsocket);
System.out.println("My Outgoing connection to " + outsocket.getInetAddress());
context.setAttribute(HTTP_OUT_CONN, outconn);
final HttpClientConnection conn = (HttpClientConnection) context.getAttribute(
HTTP_OUT_CONN);
context.setAttribute(HttpCoreContext.HTTP_CONNECTION, conn);
context.setAttribute(HttpCoreContext.HTTP_TARGET_HOST, this.target);
System.out.println(">> Request URI: " + request.getRequestLine().getUri());
// Remove hop-by-hop headers
request.removeHeaders(HTTP.CONTENT_LEN);
request.removeHeaders(HTTP.TRANSFER_ENCODING);
request.removeHeaders(HTTP.CONN_DIRECTIVE);
request.removeHeaders("Keep-Alive");
request.removeHeaders("Proxy-Authenticate");
request.removeHeaders("TE");
request.removeHeaders("Trailers");
request.removeHeaders("Upgrade");
this.httpexecutor.preProcess(request, this.httpproc, context);
final HttpResponse targetResponse = this.httpexecutor.execute(request, conn, context);
this.httpexecutor.postProcess(response, this.httpproc, context);
// Remove hop-by-hop headers
targetResponse.removeHeaders(HTTP.CONTENT_LEN);
targetResponse.removeHeaders(HTTP.TRANSFER_ENCODING);
targetResponse.removeHeaders(HTTP.CONN_DIRECTIVE);
targetResponse.removeHeaders("Keep-Alive");
targetResponse.removeHeaders("TE");
targetResponse.removeHeaders("Trailers");
targetResponse.removeHeaders("Upgrade");
response.setStatusLine(targetResponse.getStatusLine());
response.setHeaders(targetResponse.getAllHeaders());
response.setEntity(targetResponse.getEntity());
System.out.println("<< Response: " + response.getStatusLine());
final boolean keepalive = this.connStrategy.keepAlive(response, context);
context.setAttribute(HTTP_CONN_KEEPALIVE, new Boolean(keepalive));
outsocket.close();
}
}
i have changed the handler function and in it i create ,
DefaultBHttpClientConnection outconn based on the host in request URI.
As you can see i create a new socket (outsocket) using a SocketFactory .
the problem i don't know how to close the socket .
i tried closing it at the end of handle() but then i would start receiving
I/O error: Socket closed
and the proxy stops working .
The Thread that calls the httpservice.handleRequest() is identical to the one in the example in the link (i can post it if needed, i didn't cause it would take space in the question ).
I've solved the problem.
it was the line :
outconn = new DefaultBHttpClientConnection(bufsize);
inside the handler.
so every time the handler gets called it creates a new outconn .
and the one thats setup before the call to :
httpservice.handleRequest(this.inconn, context);
even if it gets shutdown it won't close the socket since it is binded to a different copy of the outconn .
If you are making a proxy, the only time you should be closing connections is if you get an IOException on one side which closes that half of the conversation; at that point, it's safe to close the other side of the conversation

Fiddler doesn't capture Apache HttpClient post

Somehow Fiddler doesn't capture the posts I send from my HttpClient provided by Apache.
But when I send the same post in C# using the HttpClient to the same server, Fiddler does intercept the sessions.
My Java code:
private DefaultHttpClient client = new DefaultHttpClient();
private HttpContext context = new BasicHttpContext();
private BasicCookieStore store = new BasicCookieStore();
public Client() throws URISyntaxException {
context.setAttribute(ClientContext.COOKIE_STORE, store);
logIn();
}
private void logIn() throws URISyntaxException {
HttpUriRequest login = RequestBuilder.post()
.setUri(new URI("http://www.derpforum.nl"))
.addParameter("username", "Kattoor4")
.addParameter("password", "XXXX")
.addHeader("Referer", "http://www.derpforum.nl/")
.build();
try (CloseableHttpResponse response = client.execute(login, context)) {
HttpEntity entity = response.getEntity();
BufferedReader reader = new BufferedReader(new InputStreamReader(entity.getContent()));
String line;
while ((line = reader.readLine()) != null)
System.out.println(line);
} catch (IOException e) {
e.printStackTrace();
}
}
Any thoughts? Thanks!
I am usring Apache HttpClient(4.5.5), SWT4 and Fiddler4, and the VM arguments method does not work for me.
So I set the proxy settings in the code and it works.
HttpHost proxy = new HttpHost("localhost", 8888, "http");
DefaultProxyRoutePlanner routePlanner = new DefaultProxyRoutePlanner(proxy);
CloseableHttpClient httpclient = HttpClients.custom()
.setRoutePlanner(routePlanner)
.build();
You probably need to configure Java to use Fiddler as a proxy either in code or by setting the relevant Java system properties as below. See this question.
-Dhttp.proxyHost=127.0.0.1
-Dhttp.proxyPort=8888

How to use a custom socketfactory in Apache HttpComponents

I have been trying to use a custom SocketFactory in the httpclient library from the Apache HTTPComponents project. So far without luck. I was expecting that I could just set a socket factory for a HttpClient instance, but it is obviously not so easy.
The documentation for HttpComponents at http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html does mention socket factories, but does not say how to use them.
Does anybody know how this is done?
oleg's answer is of course correct, I just wanted to put the information directly here, in case the link goes bad. In the code that creates a HttpClient, I use this code to let it use my socket factory:
CustomSocketFactory socketFactory = new CustomSocketFactory();
Scheme scheme = new Scheme("http", 80, socketFactory);
httpclient.getConnectionManager().getSchemeRegistry().register(scheme);
CustomSocketFactory is my own socket factory, and I want to use it for normal HTTP traffic, that's why I use "http" and 80 as parameters.
My CustomSchemeSocketFactory looks similar to this:
public class CustomSchemeSocketFactory implements SchemeSocketFactory {
#Override
public Socket connectSocket( Socket socket, InetSocketAddress remoteAddress, InetSocketAddress localAddress, HttpParams params ) throws IOException, UnknownHostException, ConnectTimeoutException {
if (localAddress != null) {
socket.setReuseAddress(HttpConnectionParams.getSoReuseaddr(params));
socket.bind(localAddress);
}
int connTimeout = HttpConnectionParams.getConnectionTimeout(params);
int soTimeout = HttpConnectionParams.getSoTimeout(params);
try {
socket.setSoTimeout(soTimeout);
socket.connect(remoteAddress, connTimeout );
} catch (SocketTimeoutException ex) {
throw new ConnectTimeoutException("Connect to " + remoteAddress + " timed out");
}
return socket;
}
#Override
public Socket createSocket( HttpParams params ) throws IOException {
// create my own socket and return it
}
#Override
public boolean isSecure( Socket socket ) throws IllegalArgumentException {
return false;
}
}
We use a custom socket factory to allow HttpClient connections to connect to HTTPS URLs with untrusted certificates.
Here is how we did it:
We adapted implementations of both the 'EasySSLProtocolSocketFactory' and 'EasyX509TrustManager' classes from the examples source directory referenced by Oleg.
In our HttpClient startup code, we do the following to enable the new socket factory:
HttpClient httpClient = new HttpClient();
Protocol easyhttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", easyhttps);
So that any time we request an https:// URL, this socket factory is used.

HTTP client - HTTP 405 error "Method not allowed". I send a HTTP Post but for some reason HTTP Get is sent

I am using the apache library. I have created a class which sends a post request to a servlet. I have set up the parameters for the client and i have created a HTTP post object to be sent but for some reason when i excute the request i get a reposnse that says the get method is not supported(which is true cause i have only made a dopost method in my servlet). It seems that a get request is being sent but i dont know why. The post method worked before but i started gettng http error 417 "Expectation Failed" due to me not setting the protocal version but i fixed this by adding paramenters.
below is my class where you see a HTTPpost object being created and exectued. I have a response handler method but i took it out of my code below because it has nothing to do with my problem.
I know a HTTP GET is being sent because of the reponse mesage that is returned says. The specified HTTP method is not allowed for the requested resource (HTTP method GET is not supported by this URL).
Thanks in advance.
P.s i am developing for android.
public class HTTPrequestHelper {
private final ResponseHandler<String> responseHandler;
private static final String CLASSTAG = HTTPrequestHelper.class.getSimpleName();
private static final DefaultHttpClient client;
static{
HttpParams params = new BasicHttpParams();
params.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);
params.setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, HTTP.UTF_8);
///params.setParameter(CoreProtocolPNames.USER_AGENT, "Android-x");
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 15000);
params.setParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false);
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(
new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(
new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ThreadSafeClientConnManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
client = new DefaultHttpClient(cm,params);
}
public HTTPrequestHelper(ResponseHandler<String> responseHandler) {
this.responseHandler = responseHandler;
}
public void performrequest(String url, String para)
{
HttpPost post = new HttpPost(url);
StringEntity parameters;
try {
parameters = new StringEntity(para);
post.setEntity(parameters);
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
BasicHttpResponse errorResponse =
new BasicHttpResponse(
new ProtocolVersion("HTTP_ERROR", 1, 1),
500, "ERROR");
try {
client.execute(post, this.responseHandler);
}
catch (Exception e) {
errorResponse.setReasonPhrase(e.getMessage());
try {
this.responseHandler.handleResponse(errorResponse);
}
catch (Exception ex) {
Log.e( "ouch", "!!! IOException " + ex.getMessage() );
}
}
}
I tried added the allow header to the request but that did not work as well but im not sure if i was doing right. below is the code.
client.addRequestInterceptor(new HttpRequestInterceptor() {
#Override
public void process(HttpRequest request, HttpContext context)
throws HttpException, IOException {
//request.addHeader("Allow", "POST");
}
});
How do you know that a HTTP GET is actually being sent? Examining the http packets sent by your client or received by the server would be helpful here
You catch and swallow UnsupportedEncodingException when constructing the Post's parameters - what happens if you encounter this exception while setting parameters? Your code as is today will still attempt to execute the POST.

Categories