0x00
Before introducing the use of NANOHTTPD to implement simple webserver, we first familiar with the next LAN socket communication. A client project with a code address of https://github.com/jltxgcy/AppVulnerability/tree/master/MyClient. A server project with a code address of https://github.com/jltxgcy/AppVulnerability/tree/master/MyServer.
Two projects to the same WiFi environment, myclient project to modify the connection target IP address. As follows:
Clientsocket = new Socket ("10.10.154.74", 6100);
This IP address can be obtained by setting the->ip address of the status information, such as the phone. Such as:
The specific code is not introduced, we analyze.
0x01
The following describes the use of nanohttpd for simple webserver. The code address is Https://github.com/jltxgcy/AppVulnerability/tree/master/NanoHttpD.
After running NANOHTTPD, the native UC browser enters http://127.0.0.1:8088 and returns it works. It works also occurs when you enter http://10.10.154.12 (that is, the mobile IP that runs NANOHTTPD) on other mobile browsers that connect to the same wifi.
So what is the principle of this local webserver?
Let's look at the main activity first, the code is as follows:
public class Mainactivity extends Activity {private simpleserver server; @Overrideprotected void OnCreate (Bundle Savedinstancestate) {super.oncreate (savedinstancestate); Setcontentview (r.layout.activity_main); server = new Simpleserver (); try {//Because the program simulates HTML placement in the asset directory,//So store the Assetmanager pointer here. Server.asset_mgr = This.getassets ();//Start Web Service Server.start (); LOG.I ("Httpd", "the server started."); catch (IOException IoE) { LOG.W ("Httpd", "The server could not start.");}} ......}
The Simpleserver object is created, and then its Start method is called. Let's look at the code for the Simpleserver class:
public class Simpleserver extends nanohttpd {Assetmanager asset_mgr; The public simpleserver () {///port is 8088, which means to visit http://127.0.0.1:8088 via the "Super" (8088); } Public Response serve (String uri, method, Map<string, string> header, Map<stri Ng, string> parameters, map<string, string> files) {int len = 0; byte[] buffer = NULL; LOG.D ("Jltxgcy", Header.get ("remote-addr")); The default incoming URL starts with "/" and needs to be removed, otherwise it becomes an absolute path String file_name = uri.substring (1); The default page name is set to Index.html if (File_name.equalsignorecase ("")) {file_name = "index.html"; } try {//Assetmanager directly open file for read operation InputStream in = Asset_mgr.open (file_name, assetmanager.access_buffer);//Assuming a single Web page text The upper limit of the size of the piece is 1MB buffer = new byte[1024*1024]; int temp=0; while ((Temp=in.read ())!=-1) {buffer[len]= (byte) temp; len++; } in.close (); } catch (IOException e) {//TODO auto-generated catch blocke.printstAcktrace ();} Returns the contents of the read file to the browser return new Nanohttpd.response (Buffer,0,len); }}
Simpleserver inherits the Start method that Nanohttpd,server.start () actually calls the NANOHTTPD class. As follows:
public void Start () throws IOException {myserversocket = new ServerSocket (); Myserversocket.bind ((hostname! = null)? New Inetsocketaddress (hostname, myport): New Inetsocketaddress (MyPort)); MyThread = new Thread (new Runnable () {@Override public void run () {do { try {final Socket finalaccept = Myserversocket.accept (); Registerconnection (finalaccept); Finalaccept.setsotimeout (socket_read_timeout); Final InputStream InputStream = Finalaccept.getinputstream (); if (InputStream = = null) {safeclose (finalaccept); Unregisterconnection (finalaccept); } else {asyncrunner.exec (new Runnable () {@Override public void Run () { OutputStream outputstream = null; try {outputstream = Finalaccept.getoutputstream (); Tempfilemanager Tempfilemanager = Tempfilemanagerfactory.create (); HTTPSession session = new HTTPSession (Tempfilemanager, InputStream, OutputStream, finalaccept.getinetaddress ()); while (!finalaccept.isclosed ()) {Session.execut E (); }} catch (Exception e) {//when the socket is Closed by the client, we throw our own socketexception//To break the "keep alive "Loop above. if (! ( E instanceof socketexception && "nanohttpd Shutdown". Equals (E.getmessage ()))){E.printstacktrace (); }} finally {Safeclose (outputstream); Safeclose (InputStream); Safeclose (finalaccept); Unregisterconnection (finalaccept); } } }); }} catch (IOException e) {}} while (!myserversocket.isclosed ()); } }); Mythread.setdaemon (TRUE); Mythread.setname ("nanohttpd Main Listener"); Mythread.start (); }
A socket Server was created,myserversocket.accept () blockingWait for the connection, when the native browser entershttp://127.0.0.1:8088, the connection is established, then the connection is processed, and the mythread thread continues to execute to Session.execute. Let's look at the code for this function:
@Override public void Execute () throws IOException {try {//Read the first 8192 bytes. The full header is should fit in here. Apache ' s default header limit is 8KB. Do not assume, a single read would get the entire header at once! byte[] buf = new Byte[bufsize]; Splitbyte = 0; Rlen = 0; {int read =-1; try {read = Inputstream.read (buf, 0, BUFSIZE); } catch (Exception e) {safeclose (InputStream); Safeclose (OutputStream); throw new SocketException ("nanohttpd Shutdown"); } if (read = =-1) {//socket was been closed safeclose (i Nputstream); Safeclose (OutputStream); Throw new SocketException ("nanohttpd Shutdown"); } while (Read > 0) {rlen + = read; Splitbyte = Findheaderend (buf, Rlen); if (Splitbyte > 0) break; Read = Inputstream.read (buf, Rlen, Bufsize-rlen); }} if (Splitbyte < Rlen) {Bytearrayinputstream Splitinputstream = NE W Bytearrayinputstream (buf, Splitbyte, rlen-splitbyte); Sequenceinputstream Sequenceinputstream = new Sequenceinputstream (Splitinputstream, InputStream); InputStream = Sequenceinputstream; } parms = new hashmap<string, string> (); if (null = = headers) {headers = new hashmap<string, string> (); }//Create a BufferedReader for parsing the header. BufferedReader hin = new BufferedReader (new InputStreamReader (New Bytearrayinputstream (buf, 0, Rlen)); Decode the header into Parms and header Java Properties map<string, string> pre = new Hashma P<string, string> (); Decodeheader (Hin, Pre, parms, headers); method = Method.lookup (Pre.get ("method")); if (method = = null) {throw new Responseexception (Response.Status.BAD_REQUEST, "Bad Request:syntax err Or. ");} URI = Pre.get ("uri"); cookies = new Cookiehandler (headers); Ok, now does the serve () Response R = Serve (this); if (r = = null) {throw new Responseexception (Response.Status.INTERNAL_ERROR, "SERVER INTERNAL error:se Rve () returned a null response. "); else {cookies.unloadqueue (R); R.setrequestmethod (method); R.send (OutputStream); }} catch (SocketException e) {//Throw it out to close socket object (finalaccept) Throw e; } catch (Sockettimeoutexception ste) {throw Ste; } catch (IOException IoE) {Response r = new Response (Response.Status.INTERNAL_ERROR, Mime_plaintext, "SERV ER INTERNAL error:ioexception: "+ ioe.getmessage ()); R.send (OutputStream); Safeclose (OutputStream); } catch (Responseexception re) {Response r = new Response (Re.getstatus (), Mime_plaintext, Re.getmessage ()) ; R.send (OutputStream); Safeclose (OutputStream); } finally {tempfilemanager.clear (); } }
This function parseshttp://127.0.0.1:8088, and then calls the Simpleserver serve method, which returns the content that is displayed in the browser.
We look at the public Response serve (String uri, method, Map<string, string> header, Map<string, String> PA, depending on the debug) Rameters, map<string, string> files), what are the values returned by these parameters?
The URL is/,method to Get,head for {ACCEPT=TEXT/HTML,APPLICATION/XHTML+XML,APPLICATION/XML;Q=0.9,*/*;Q=0.8,UC/145,PLUGIN/1, Alipay/un, Accept-encoding=gzip, host=127.0.0.1:8088, ACCEPT-LANGUAGE=ZH-CN, http-client-ip=127.0.0.1, Cache-control=max-age=0, X-UCBROWSER-UA=DV (Nexus 6);p R (ucbrowser/10.7.0.634), ov (Android 5.1.1), SS (411*683);p I ( 1440*2392), Bt (UM);p m (1), BV (1), NM (0); im (0); Sr (0); NT (2);, remote-addr=127.0.0.1, user-agent=mozilla/5.0 (Linux; U Android 5.1.1; ZH-CN; Nexus 6 build/lmy47z) applewebkit/534.30 (khtml, like Gecko) version/4.0 ucbrowser/10.7.0.634 u3/0.8.0 Mobile safari/534. The connection=keep-alive},parameters is {nanohttpd.query_string=null},files {}.
If the requested address is http://127.0.0.1:8088/adv?d=1, the URL is adv,parameter {d=1, nanohttpd.query_string=d=1}.
Use nanohttpd for simple webserver