Java shutdown http server after receiving request - java

I have a setup a simple http server in java that only deals with one type of post request.
The server code:
int port = 5555;
HttpServer server = HttpServer.create(new InetSocketAddress(port), 0);
System.out.println("server started at " + port);
server.createContext("/echoPost", new echoPost());
server.setExecutor(null);
server.start();
The echoPost() class:
public class echoPost implements HttpHandler {
#Override
public void handle(HttpExchange http) throws IOException {
InputStreamReader inputStreamReader = new InputStreamReader(http.getRequestBody(), "utf-8");
BufferedReader bufferReader = new BufferedReader(inputStreamReader);
String incoming = br.readLine();
System.out.println(incoming);
String response = "response";
http.sendResponseHeaders(200, response.length());
OutputStream outputStream = http.getResponseBody();
os.write(response.toString().getBytes());
os.close();
}
}
I want the server to stop after a post request is received. Is there a way to do this so straight after one post request is handled the server stops?

What's wrong with calling server.stop(delay), where the delay is small enough (0 or 1)? You'll need to pass server as argument to the echoPost constructor.

Use
System.exit(0);
It doesn't matter where this line of code is executed, it will terminate the JVM and quit.

Related

Loading Image View From Http Server

Sorry im totally New to the Http, i Hardly Could Write a Http Server With Examples i have seen, and Im Trying to Download Images from this Http Server with Picasso Lib, but it seems Doesnt Work, here is my Server :
my content is : D:\Users\Default and im trying to load Default.jpg into iv:
public class SimpleHttpServer {
public static void main(String[] args) throws Exception {
HttpServer server = HttpServer.create(new InetSocketAddress(8000), 0);
server.createContext("/info", new InfoHandler());
server.createContext("/get", new GetHandler());
server.setExecutor(null); // creates a default executor
server.start();
}
static class InfoHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
String response = "Use /get to download an Image";
t.sendResponseHeaders(200, response.length());
OutputStream os = t.getResponseBody();
os.write(response.getBytes());
os.close();
}
}
static class GetHandler implements HttpHandler {
public void handle(HttpExchange t) throws IOException {
// add the required response header for an Image file
Headers h = t.getResponseHeaders();
h.add("Content-Type", "image/jpg");
// a PDF (you provide your own!)
File file = new File ("D:/Users/Default/Default.jpg");
byte [] bytearray = new byte [(int)file.length()];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
bis.read(bytearray, 0, bytearray.length);
// ok, we are ready to send the response.
t.sendResponseHeaders(200, file.length());
OutputStream os = t.getResponseBody();
os.write(bytearray,0,bytearray.length);
os.close();
}
}
}
and loading it from picasso like this:
Picasso.with(getActivity()).load(Uri.parse("http://192.168.1.103:8000/D:/Users
/Default/Default.jpg")).into(iv);
Which are my Mistakes and how funny they are? :P
Well first off, you hard-coded the file that the server will return, so you don't need the file location in your Uri.... you would use /get at the end... it even says so in your code... String response = "Use /get to download an Image";. Also, you need to add:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
to your manifest file if you have not already... It would be helpful FYI to post a log, not just ask whats wrong and not give any hints.

Sending HTTPS request to Chrome sync service - getting error 404

I'm trying to send a POST request to the Chrome sync service which is located at https://clients4.google.com.
I'm using that short piece of code to send a request that I captured before with the help of BURP Suite and saved to a file. It's what Chrome sends when connecting to the sync service.
That code opens an SSLSocket, connects to the Chrome server and sends the contents of that file (see below):
private void sendRequest() {
SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
SSLSocket socket = (SSLSocket) sslsocketfactory.createSocket("clients4.google.com", 443);
socket.startHandshake();
BufferedWriter out = new BufferedWriter(
new OutputStreamWriter(socket.getOutputStream(), "UTF8"));
BufferedReader in = new BufferedReader(
new InputStreamReader(socket.getInputStream()));
sendMessage(out, new File("request.bin"));
readResponse(in);
out.close();
in.close();
}
private void sendMessage(BufferedWriter out, File request) throws IOException {
List<String> result = getContents(request);
for (String line : result) {
out.write(line + "\r\n");
}
out.write("\r\n");
out.flush();
}
private void readResponse(BufferedReader in) throws IOException {
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
}
private List getContents(File file) throws IOException {
List<String> contents = new ArrayList<String>();
BufferedReader input = new BufferedReader(new FileReader(file));
String line;
while ((line = input.readLine()) != null) {
contents.add(line);
}
input.close();
return contents;
}
The request.bin file looks like this (it's a plaintext request without SSL):
POST /chrome-sync/command/?client=Google+Chrome&client_id={VALID_CLIENT_ID} HTTP/1.1
Host: clients4.google.com
Connection: keep-alive
Content-Length: 1730
Authorization: GoogleLogin auth={MY_VALID_AUTH_DATA}
Content-Type: application/octet-stream
User-Agent: Chrome WIN 23.0.1271.97 (171054)
Accept-Encoding: gzip,deflate,sdch
Accept-Language: de-DE,de;q=0.8,en-US;q=0.6,en;q=0.4
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3
{binary data}
Now this request fails as the server returns HTTP/1.0 404 Not Found.
But why does this happen?
It's the exact same request Chrome sends, isn't it? What am I missing here?
Answering my own question here: The problem was with the encoding. The binary data in the request body got slightly modified and that caused the Google server to respond with errorcode 404 (which is pretty confusing).
Now that I'm using proper encoding everything works fine.
if you input chrome://sync/ in your chrome's addr bar, you will see the server url is:
https://clients4.google.com/chrome-sync/dev
some more information you can find in this link:
http://code.google.com/p/chromium/issues/detail?id=90811
And /command? needs authentication. I found some info may be helpful for you. Check the comments of this issue:
http://code.google.com/p/chromium/issues/detail?id=108186
hope it helps

How do I write to an OutputStream using DefaultHttpClient?

How do I get an OutputStream using org.apache.http.impl.client.DefaultHttpClient?
I'm looking to write a long string to an output stream.
Using HttpURLConnection you would implement it like so:
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
OutputStream out = connection.getOutputStream();
Writer wout = new OutputStreamWriter(out);
writeXml(wout);
Is there a method using DefaultHttpClient similar to what I have above? How would I write to an OutputStream using DefaultHttpClient instead of HttpURLConnection?
e.g
DefaultHttpClient client = new DefaultHttpClient();
OutputStream outstream = (get OutputStream somehow)
Writer wout = new OutputStreamWriter(out);
I know that another answer has already been accepted, just for the record this is how one can write content out with HttpClient without intermediate buffering in memory.
AbstractHttpEntity entity = new AbstractHttpEntity() {
public boolean isRepeatable() {
return false;
}
public long getContentLength() {
return -1;
}
public boolean isStreaming() {
return false;
}
public InputStream getContent() throws IOException {
// Should be implemented as well but is irrelevant for this case
throw new UnsupportedOperationException();
}
public void writeTo(final OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
writeXml(writer);
writer.flush();
}
};
HttpPost request = new HttpPost(uri);
request.setEntity(entity);
You can't get an OutputStream from BasicHttpClient directly. You have to create an HttpUriRequest object and give it an HttpEntity that encapsulates the content you want to sent. For instance, if your output is small enough to fit in memory, you might do the following:
// Produce the output
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(out, "UTF-8");
writeXml(writer);
// Create the request
HttpPost request = new HttpPost(uri);
request.setEntity(new ByteArrayEntity(out.toByteArray()));
// Send the request
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
If the data is large enough that you need to stream it, it becomes more difficult because there's no HttpEntity implementation that accepts an OutputStream. You'd need to write to a temp file and use FileEntity or possibly set up a pipe and use InputStreamEntity
EDIT See oleg's answer for sample code that demonstrates how to stream the content - you don't need a temp file or pipe after all.
This worked well on android. It should also work for large files, as no buffering is needed.
PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream();
out.connect(in);
new Thread() {
#Override
public void run() {
//create your http request
InputStreamEntity entity = new InputStreamEntity(in, -1);
request.setEntity(entity);
client.execute(request,...);
//When this line is reached your data is actually written
}
}.start();
//do whatever you like with your outputstream.
out.write("Hallo".getBytes());
out.flush();
//close your streams
I wrote an inversion of Apache's HTTP Client API [PipedApacheClientOutputStream] which provides an OutputStream interface for HTTP POST using Apache Commons HTTP Client 4.3.4.
Calling-code looks like this:
// Calling-code manages thread-pool
ExecutorService es = Executors.newCachedThreadPool(
new ThreadFactoryBuilder()
.setNameFormat("apache-client-executor-thread-%d")
.build());
// Build configuration
PipedApacheClientOutputStreamConfig config = new
PipedApacheClientOutputStreamConfig();
config.setUrl("http://localhost:3000");
config.setPipeBufferSizeBytes(1024);
config.setThreadPool(es);
config.setHttpClient(HttpClientBuilder.create().build());
// Instantiate OutputStream
PipedApacheClientOutputStream os = new
PipedApacheClientOutputStream(config);
// Write to OutputStream
os.write(...);
try {
os.close();
} catch (IOException e) {
logger.error(e.getLocalizedMessage(), e);
}
// Do stuff with HTTP response
...
// Close the HTTP response
os.getResponse().close();
// Finally, shut down thread pool
// This must occur after retrieving response (after is) if interested
// in POST result
es.shutdown();
Note - In practice the same client, executor service, and config will likely be reused throughout the life of the application, so the outer prep and close code in the above example will likely live in bootstrap/init and finalization code rather than directly inline with the OutputStream instantiation.

HTTP server capable of Keep-Alive

I'm trying to create a http server in Java which is capable of providing keep-alive connections. I'm using the com.sun.net.httpserver.HttpServer class.
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class httpHandler implements HttpHandler {
private String resp = "<?xml version='1.0'?><root-node></root-node>";
private OutputStream os = null;
public void handle(HttpExchange t) throws IOException {
System.out.println("Handling message...");
java.io.InputStream is = t.getRequestBody();
System.out.println("Got request body. Reading request body...");
byte[] b = new byte[500];
is.read(b);
System.out.println("This is the request: " + new String(b));
String response = resp;
Headers header = t.getResponseHeaders();
header.add("Connection", "Keep-Alive");
header.add("Keep-Alive", "timeout=14 max=100");
header.add("Content-Type", "application/soap+xml");
t.sendResponseHeaders(200, response.length());
if(os == null) {
os = t.getResponseBody();
}
os.write(response.getBytes());
System.out.println("Done with exchange. Closing connection");
os.close();
}
public static void main(String[] args) {
HttpServer server = null;
try {
server = HttpServer.create(new InetSocketAddress(8080), 5);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
server.createContext("/", new httpHandler());
server.setExecutor(null); // creates a default executor
System.out.println("Starting server...");
server.start();
}
}
The client does not close the connection. The server seems to close it instead directly after the exchange has occurred. I tried deleting the os.close line but then the server will not reply to the second request. But it doesn't close it either. I have a feeling it involves doing something in the main code with the server object but I have no idea what. Google isn't turning up much either.
Anyone here got any ideas? Any help would be much appreciated.
It looks like the problem is you didn't drain all data from request. You should keep doing is.read() until it returns -1, then close it.
Since you didn't drain the request, there are still bytes left. The server cannot simply "jump" to the next request; it's not like a disk, more like a tape. Server has to read(and discard) all data from current request, before the it can reach the next request.
Without a limit this can be used to attack the server; so the server would only attempt to drain up to a limit, which is 64K by default. You are probably receiving a request bigger than 64K.
Usually the handler should read the entire request first. Otherwise how does it know how to serve the request?
More seriously, if the request is not drained first, deadlock can happen. Clients are typically simple: they writes the request, then read the response. If the server writes the response before it reads all the request, the client could be still writing the request. Both are writing to each other but neither is reading. If buffers are full then we are in a deadlock, both are blocked on write. Note there's no timeout for write()!
Why do you get the ResponseBody OutputStream only if the previous was null?
if(os == null) {
os = t.getResponseBody();
}
Might be better to get the OutputStream each time as you cannot be sure if the previous one is identical to the one of current Request.
try to call t.close(), the server will reply
It's the client that sends the keep-alive headers. If it does that, HttpServer doesn't close the connection. You don't have to do anything about it.

Implementing custom HTTP methods with HttpCore

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.

Categories