I have an assignment where I need to create a Proxy server, that will manipulate some of the requests/responses it gets, implement caching, etc.
For starters, I want to create the simplest proxy, that simply passes on all requests and responses. I've done some searches online and I am a bit confused on how to listen to requests in a certain port and get the HTTP requests. I've stumbled on the classes Socket, ServerSocket, HttpURLConnection, but I'm not sure how all these interact. I tried to read the docs, but they are all intertwined and a bit hard to understand.
Can you point me in the right direction regarding which classes I should probably use for this assignment, and maybe share a snippet for listening on a port, getting HTTP request headers, etc.?
Well, I can only assume that your Proxy will be a ServerSocket listening for requests on the HTTP port. You read the request through the server socket input stream. After checking the request is compliant with the proxy's rules you will open a HttpConnection to the real HTTP Server, and using the output stream in the http connection you will forward the client's request, then using the http connection input stream, you read the real HTTP Server's response, which you will ultimately forward back to the client using the socket's output stream.
In the proxy, since you intercept requests and responses you can manipulate them before forwarding.
Sounds right?
Here's some introductory Java socket material: http://www.oracle.com/technetwork/java/socket-140484.html
Related
I am using Apache HTTP client to contact an external service. The service can take a few hours, if not longer, to generate its response. I've tried a few different things but have either ended up with socket or read timeouts. I've just tried using the RequestConfig to set the socket and connection timeout to 0 which according to the documentation should be infinite but the request always returns after exactly 1 hour. Any thoughts?
I agree with general sentiments about not trying to keep HTTP connections alive so long, however, if your hands are tied, you may find you are hitting timeouts in TCP and TCP level keep-alives may save the day.
See this link for help setting TCP keep-alive, you cannot do it in HttpClient its an OS thing, this will send ACKs regularly so your TCP connection is never idle even if nothing is going on in the HTTP stream.
Apache HttpClient TCP Keep-Alive (socket keep-alive)
Holding TCP connections for a long time even if they are active is hard. YMMV.
Ideally, any service that takes more then few minutes(2-3 minutes+ or so), should be handled asynchronously, instead keeping connection open for an hour or so long. It is waste of resources both client and server side.
Alternate approaches could be to solve these kind of problems.
You call the service to trigger processing(to prepare response). It may return you some unique request ID.
Then after an hour or so(once response is ready with response), either client request again by passing the request ID, and server returns the Response.
Other alternate approach could be, once response it ready, it pushes back the response to Callback URL or something where Client host another service specifically for receiving the response prepared by the server(step#1).
I am using embedded jetty and spring for java to java communication over http. My problem is that my server application must handle plain TCP messages also on the same port.
Is there a way to detect if a TCP message arrived which cannot be handled by the servlet?
Thanks for the answers I add some more details:
I cannot modify the client. The reason for this is that the old version of the client uses pure java tcp socket and it turned out that the new server must be backward compatible with the old client.
Have to use the same port
Old client messages are short serialized text over simple socket. 1: open connection, 2: send text, 3: close connection
My server looks something like this: http://kielczewski.eu/2013/11/using-embedded-jetty-spring-mvc/
I do not need to parse the message. It is enough to detect that a message was arrived which is not using http and get the source host name.
You might want to take a look at how to add a custom ConnectionFactory to the ServerConnector of your HTTP port.
This ConnectionFactory concept is how the PROXY Protocol is supported within Jetty currently.
In your case, you might have something like ...
MyTcpConnectionFactory tcpConnectionFactory = new MyTcpConnectionFactory();
ServerConnector http = new ServerConnector(server);
http.addFirstConnectionFactory(tcpConnectionFactory);
server.addConnector(http);
In your case, you would override the newConnection(Connector connector, EndPoint endPoint) method and implement the check for your TCP flow, or the HTTP flow.
If its your flow, you handle the communications on that connection yourself and then throw an IOException when you are done indicating that you don't want jetty to process that connection as HTTP.
Otherwise you return that Connection object to Jetty to process as HTTP.
You are in for a wild ride here my friend. You need to realize that HTTP IS TCP ... its just the content being sent on the TCP socket that classifies it as HTTP or not. That being said, you can intercept the Connection with a filter ie
1) create a filter (google Java Application Server Filters and check the Jetty implementation) for ALL incoming connections
2) check for URI on the request, if it fails, then the request is not HTTP (might want to double check on the request testing logic here)
3) Redirect the request to the appropriate Servlet / Function based on serial socket / http request
On another note, why not use https (port 443) for http and port 80 for your socket requirments ?
I stand corrected. Filters wont work.
In that case, you will have to code a mini firewall. you have to scan all inputs for https headers and redirect accordingly. Can you at least provide some context on the plain TCP messages you want to receive? do you have any control over the sending code ? you do know you can upgrade a TCP/HTTP connection to a websocket (involves client and server) and it will work even better than plain TCP, same port connections, and comes built in Jetty so no custom boiler plates, just a websocket servlet
It's very annoying when you are making a simple socket server and you get an http request. Very anoying if your server doesn't support http requests. Is there a way to detect and deny http requests (from webbrowsers) and only accept tcp/socket connections?
no, because you dont know the payload a client intends to send over a socket until youve accepted the connection and read enough of it to understand its talking HTTP.
In my opinion you should think of the frustration clients are experiencing, and do 2 things:
Why are browsers being directed to your (obviously not http) service? can you stop it?
Assuming the answer to #1 above is no, maybe implement some simple detection for http requests and respond with a hardcoded http response that renders as a readable error on the browser who sent it? (yes, even though your service isnt http) - a simple detection would be take your input buffer, decode as a us-ascii string, and if it starts with one of the 9 HTTP request methods send out some hardcoded http error response. i suggest error code 402 - payment required :-)
I have not worked with HTTP post/get before, my up coming project in my office is based on http post/get in java. Its basically client - server based application. the client will post some info and I need to get that info and process the string and vice-verse. this project has to be developed on J2SE. You can assume this some thing like a JMS queue message processing stuff. I googled for the info but most of the information was for web application, mine should work like a message queue. Can someone explain me how to do this or point me where I can get some useful info.
Thanks
Arun
Well, if you don't need to specifically use strict HTTP, and you need to just use Java SE (and not Java EE, which rules out Servlets, JSPs, JMS, etc), then you need to probably investigate ServerSocket and Socket classes.
Server
Your server would need to listen on a TCP port (say, port 8080) - usually you would pick a port number between 1025 and 65,535, however if you are attempting to use an already defined service that has a default port, then use that. Note however, that on unix, in order to listen on any port below 1024, I believe you need to be root. Traditionally, port 80 is used for HTTP.
To listen on this port, you would need something like this in your code:
ServerSocket srvSocket = new ServerSocket(8080);
Socket socket = srvSocket.accept();
This pretty much the most basic code that would cause your application to wait until something connected to port 8080. Once connected, you could obtain both an InputStream and OutputStream for your connected client, by interrogating the returned socket object, allowing you to read content from the client, and inserting these requests in a queue. This queue could be then processed by some other Thread.
Client
In order for your client to connect to the server, you would need to use something based on the following example:
Socket connection = new Socket("server.domain.com", 8080);
OutputStream output = connection.getOutputStream();
You would then write your request to the server into the OutputStream (and read from the InputStream returned from getInputStream() if you expected a response)
The code supplied is pretty basic, but it should give you a rough idea of how to proceed. You can even use this method if you wanted to use real HTTP, however it might be a better idea to use some premade library if that was the case (although its probable that you're not going to require all functionality defined in the HTTP spec itself).
Anyway, I hope that provides you a good starting point from which to build.
Jetty is a popular web server, designed to easily be embedded in an application.
Its HTTP server component can run inside your application and respond to requests by dispatching to your custom code.
Jetty also features an HTTP client that you can use on the client side to send requests.
This is a rather big topic and I won't be able to post a complete guide, but Jetty's documentation is generally of very high quality and should be a good starting point.
I suggest you start with learning the basics of HTTP protocol. This article is a good starter. After you understood the basics follow the this article on how to programatically communicate (read/write) with HTTP servers. After that Google is your friend.
If you weren't restricted to J2SE, you could use Servlets for managing the POST/GET methods of HTTP. Evaluate if it is possible, otherwise you'd be reinventing the wheel
I also have a mainly SE background. On the client side, writing get/post is pretty easy. Or you can Google to find source code. I found that using REST was straightforward and understandable. On the server side, there are many options and I have very limited experience. I wrote the server using standard JEE6 and it wasn't too painful, but sounds like that is not an option for you.
I am looking into trying to do UDP/TCP hole punching using a servlet running on Google's AppEngine.
I would be using primarily the Java EE library. But I don't quite see how to forward a network connection request from the client to the other client who is acting as the P2P "host".
Is there something I'm missing in the ServletRequest/ServletResponse classes?
Don't think you're going to be able to handle UDP. However, for TCP, if you override the service method in the servlet and handle the "CONNECT" verb, you can then read from and write to the input and output streams. From the client side, you should be able to utilize this through a HttpURLConnection or something like Apache HTTP Client.