Saturday, January 31, 2015

Simple web server provide image download, using org.apache.http.protocol.HttpService

Last post show a "Simple web server using org.apache.http.protocol.HttpService". In this post, I tried to provide image download, by visiting http://<ip address>:8080/image

But FAIL - As shown in the video, sometimes the download will fail. And once fail, the code will block and have to be re-start. Hope anybody can advise.


Modify MainActivity.java
package com.example.androidhttpservice;

import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.Enumeration;

import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.entity.ContentProducer;
import org.apache.http.entity.EntityTemplate;
import org.apache.http.entity.FileEntity;
import org.apache.http.impl.DefaultConnectionReuseStrategy;
import org.apache.http.impl.DefaultHttpResponseFactory;
import org.apache.http.impl.DefaultHttpServerConnection;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import org.apache.http.protocol.HttpRequestHandlerRegistry;
import org.apache.http.protocol.HttpService;
import org.apache.http.protocol.ResponseConnControl;
import org.apache.http.protocol.ResponseContent;
import org.apache.http.protocol.ResponseDate;
import org.apache.http.protocol.ResponseServer;

import android.support.v7.app.ActionBarActivity;
import android.widget.TextView;
import android.os.Bundle;
import android.os.Environment;

/*
 * Permission needed:
 * "android.permission.INTERNET"
 * "android.permission.READ_EXTERNAL_STORAGE"
 */

public class MainActivity extends ActionBarActivity {

 HttpServiceThread httpServiceThread;
 
 TextView infoIp;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);

  infoIp = (TextView) findViewById(R.id.infoip);
  infoIp.setText(getIpAddress() + ":" 
    + HttpServiceThread.HttpServerPORT + "\n");

  httpServiceThread = new HttpServiceThread();
  httpServiceThread.start();
 }

 @Override
 protected void onDestroy() {
  super.onDestroy();
  httpServiceThread.stopServer();
 }

 private String getIpAddress() {
  String ip = "";
  try {
   Enumeration<NetworkInterface> enumNetworkInterfaces = NetworkInterface
     .getNetworkInterfaces();
   while (enumNetworkInterfaces.hasMoreElements()) {
    NetworkInterface networkInterface = enumNetworkInterfaces
      .nextElement();
    Enumeration<InetAddress> enumInetAddress = networkInterface
      .getInetAddresses();
    while (enumInetAddress.hasMoreElements()) {
     InetAddress inetAddress = enumInetAddress.nextElement();

     if (inetAddress.isSiteLocalAddress()) {
      ip += "SiteLocalAddress: "
        + inetAddress.getHostAddress() + "\n";
     }

    }

   }

  } catch (SocketException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
   ip += "Something Wrong! " + e.toString() + "\n";
  }

  return ip;
 }

 private class HttpServiceThread extends Thread {

  ServerSocket serverSocket;
  Socket socket;
  HttpService httpService;
  BasicHttpContext basicHttpContext;
  static final int HttpServerPORT = 8080;
  boolean RUNNING = false;

  HttpServiceThread() {
   RUNNING = true;
   startHttpService();
  }

  @Override
  public void run() {

   try {
    serverSocket = new ServerSocket(HttpServerPORT);
    serverSocket.setReuseAddress(true);

    while (RUNNING) {
     socket = serverSocket.accept();
     
     DefaultHttpServerConnection httpServerConnection = new DefaultHttpServerConnection();
     httpServerConnection.bind(socket, new BasicHttpParams());
     httpService.handleRequest(httpServerConnection,
       basicHttpContext);
     httpServerConnection.shutdown();
    }
    serverSocket.close();
   } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   } catch (HttpException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
   }
  }

  private synchronized void startHttpService() {
   BasicHttpProcessor basicHttpProcessor = new BasicHttpProcessor();
   basicHttpContext = new BasicHttpContext();

   basicHttpProcessor.addInterceptor(new ResponseDate());
   basicHttpProcessor.addInterceptor(new ResponseServer());
   basicHttpProcessor.addInterceptor(new ResponseContent());
   basicHttpProcessor.addInterceptor(new ResponseConnControl());

   httpService = new HttpService(basicHttpProcessor,
     new DefaultConnectionReuseStrategy(),
     new DefaultHttpResponseFactory());

   HttpRequestHandlerRegistry registry = new HttpRequestHandlerRegistry();
   registry.register("/", new HomeCommandHandler());
   registry.register("/image", new ImageCommandHandler());
   httpService.setHandlerResolver(registry);
  }

  public synchronized void stopServer() {
   RUNNING = false;
   if (serverSocket != null) {
    try {
     serverSocket.close();
    } catch (IOException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
    }
   }
  }

  class HomeCommandHandler implements HttpRequestHandler {

   @Override
   public void handle(HttpRequest request, HttpResponse response,
     HttpContext httpContext) throws HttpException, IOException {

    HttpEntity httpEntity = new EntityTemplate(
      new ContentProducer() {

       public void writeTo(final OutputStream outstream)
         throws IOException {

        OutputStreamWriter outputStreamWriter = new OutputStreamWriter(
          outstream, "UTF-8");
        String response = "<html><head></head><body><h1>Hello HttpService, from Android-er<h1></body></html>";

        outputStreamWriter.write(response);
        outputStreamWriter.flush();
       }
      });
    response.setHeader("Content-Type", "text/html");
    response.setEntity(httpEntity);
   }

  }
  
  class ImageCommandHandler implements HttpRequestHandler {

   @Override
   public void handle(HttpRequest request, HttpResponse response,
     HttpContext context) throws HttpException, IOException {

    File file = new File(
      Environment.getExternalStorageDirectory(), 
      "android-er_sketch.jpg");

                FileEntity fileEntity = new FileEntity(file, "image/jpg");
                response.setHeader("Content-Type", "application/force-download");
                response.setHeader("Content-Disposition","attachment; filename=image.jpg");
    response.setHeader("Content-Type", "image/jpg");
    response.setEntity(fileEntity);
   }
   
  }

 }

}

Layout file, activity_main.xml, refer to last post.

Permission of "android.permission.INTERNET" and "android.permission.READ_EXTERNAL_STORAGE" is needed in AndroidManifest.xml.

download filesDownload the files.

2 comments:

Anonymous said...

Thanks for the details.

But I keep getting connection Reset error when I try to download the image on client side URL.

Please let me know if anything which has been fixed to sort that issue.

Regards,
Raghu

Anonymous said...

Hello,

Sorry for my previous comment but i wasn't googling right things. You already answered me with that example ;) It really helped me to understand how connection works and now I'm able to make my own app.