Search code examples
androidnanohttpd

Why images and style files couldn't found on NanoHTTPD


PROBLEM : I'm using NanoHTTPD . It's working great but it's not serving .js files, images and others.

DETAILED EXPLANATION : i have a pages folder inside of assets folder. This folder containing index.html, css files, images and others. I'm using NanoHTTPD like this, but when i browse with my browser, there aren't any styles or images. Server can't found images and other files. There is only index.html file's content. Activity :

MyHTTPD server = null;
        try {
            server = new MyHTTPD(getApplicationContext());
            try
               {
                   server.start();
               }
               catch( IOException ioe )
               {
                   System.err.println( "Couldn't start server:\n" + ioe );
                   System.exit( -1 );
               }
               System.out.println( "Listening on port 8080. Hit Enter to stop.\n" );
               try { System.in.read(); } catch( Throwable t ) {
                   System.out.println("read error");
               };
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

MyHTTPD class

public Context ctx = null;
    /**
    * Constructs an HTTP server on given port.
    */
   public MyHTTPD(Context ctx) throws IOException {
       super(8080);
       this.ctx = ctx;
   }


@Override
   public Response serve( String uri, Method method,
           Map<String, String> header, Map<String, String> parms,
           Map<String, String> files )
           {
            String html = null;
            InputStream is = null;
            try {
                is = ctx.getAssets().open("pages/index.html");
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            byte[] b;
            try {
                b = new byte[is.available()];
                is.read(b);
                html = new String(b);
            } catch (IOException e) { // TODO Auto-generated catch block
                e.printStackTrace();
            }
               return new NanoHTTPD.Response(html);
           }

NOTE : I've read this questions (and answers) : Using NanoHTTPD in Android file uploading error nanohttpd How to create nanohttpd server in android?


Solution

  • in my serve() method it looks like this:

                     @Override
                public Response serve(String uri, String method, Properties header, Properties parms, Properties files) {
                           Log.d(TAG,"SERVE ::  URI "+uri);
                  final StringBuilder buf = new StringBuilder();
                  for (Entry<Object, Object> kv : header.entrySet())
                    buf.append(kv.getKey() + " : " + kv.getValue() + "\n");
                  InputStream mbuffer = null;
    
    
    
                                try { 
                                        if(uri!=null){
    
                                           if(uri.contains(".js")){
                                                   mbuffer = mContext.getAssets().open(uri.substring(1));
                                                   return new NanoHTTPD.Response(HTTP_OK, MIME_JS, mbuffer);
                                           }else if(uri.contains(".css")){
                                                   mbuffer = mContext.getAssets().open(uri.substring(1));
                                                   return new NanoHTTPD.Response(HTTP_OK, MIME_CSS, mbuffer);
    
                                           }else if(uri.contains(".png")){
                                                   mbuffer = mContext.getAssets().open(uri.substring(1));      
                                                   // HTTP_OK = "200 OK" or HTTP_OK = Status.OK;(check comments)
                                                   return new NanoHTTPD.Response(HTTP_OK, MIME_PNG, mbuffer);
                                           }else if (uri.contains("/mnt/sdcard")){
                                                   Log.d(TAG,"request for media on sdCard "+uri);
                                                   File request = new File(uri);
                                                   mbuffer = new FileInputStream(request);
                                                   FileNameMap fileNameMap = URLConnection.getFileNameMap();
                                                   String mimeType = fileNameMap.getContentTypeFor(uri);
    
                                                   Response streamResponse = new Response(HTTP_OK, mimeType, mbuffer);
                                                   Random rnd = new Random();
                                    String etag = Integer.toHexString( rnd.nextInt() );
                                    streamResponse.addHeader( "ETag", etag);
                                                   streamResponse.addHeader( "Connection", "Keep-alive");
    
    
    
    
    
    
                                                   return streamResponse;
                                           }else{
                                                   mbuffer = mContext.getAssets().open("index.html");
                                                   return new NanoHTTPD.Response(HTTP_OK, MIME_HTML, mbuffer);
                                           }
                                        }
    
                                } catch (IOException e) {
                                        Log.d(TAG,"Error opening file"+uri.substring(1));
                                        e.printStackTrace();
                                }
    
                          return null;
    
                }
    

    There is some not so clean solution with mime types. Validation should be done with something like this Getting A File's Mime Type In Java, I my simple project I am just checking few kinds of mime.
    Reference mime types are static fields in NanoHTTPD class:

           /**
         * Common mime types for dynamic content
         */
        public static final String
                MIME_PLAINTEXT = "text/plain",
                MIME_HTML = "text/html",
                MIME_JS = "application/javascript",
                MIME_CSS = "text/css",
                MIME_PNG = "image/png",
                MIME_DEFAULT_BINARY = "application/octet-stream",
                MIME_XML = "text/xml";
    

    With this implementation I was able to read files from assets as well as from external memory.