diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml deleted file mode 100644 index 7d3a33c..0000000 --- a/.idea/deploymentTargetDropDown.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 526b4c2..a2d7c21 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -13,7 +13,6 @@ - diff --git a/app/build.gradle b/app/build.gradle index 2d3ec1b..a5de708 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -9,9 +9,9 @@ android { defaultConfig { applicationId "com.peernet.mobile" minSdk 24 - targetSdk 31 - versionCode 1 - versionName "1.0" + targetSdk 32 + versionCode 2 + versionName "2.0" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } @@ -36,18 +36,18 @@ android { dependencies { - implementation 'androidx.core:core-ktx:1.7.0' - implementation 'androidx.appcompat:appcompat:1.4.0' - implementation 'com.google.android.material:material:1.4.0' - implementation 'androidx.constraintlayout:constraintlayout:2.1.2' + implementation 'androidx.core:core-ktx:1.8.0' + implementation 'androidx.appcompat:appcompat:1.4.2' + implementation 'com.google.android.material:material:1.6.1' + implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'com.android.volley:volley:1.2.1' - implementation 'androidx.navigation:navigation-fragment-ktx:2.3.5' - implementation 'androidx.navigation:navigation-ui-ktx:2.3.5' + implementation 'androidx.navigation:navigation-fragment-ktx:2.4.2' + implementation 'androidx.navigation:navigation-ui-ktx:2.4.2' testImplementation 'junit:junit:4.+' androidTestImplementation 'androidx.test.ext:junit:1.1.3' androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0' implementation (name:'mobile', ext:'aar') implementation 'com.vmadalin:easypermissions-ktx:1.0.0' - implementation 'com.squareup.okhttp3:okhttp:3.8.1' + implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2' //compile 'io.github.rybalkinsd:kohttp:0.10.0' } \ No newline at end of file diff --git a/app/libs/mobile-sources.jar b/app/libs/mobile-sources.jar index ccb0289..701a1ee 100644 Binary files a/app/libs/mobile-sources.jar and b/app/libs/mobile-sources.jar differ diff --git a/app/libs/mobile.aar b/app/libs/mobile.aar index 6d027bb..d501ccf 100644 Binary files a/app/libs/mobile.aar and b/app/libs/mobile.aar differ diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c201f48..88c87c4 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,6 +11,8 @@ + + interfaces; + try { + interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); + } catch (Exception e) { + return ""; + } + + StringBuilder sb = new StringBuilder(""); + for (NetworkInterface nif : interfaces) { + try { + // Android doesn't have a supportsBroadcast() but the Go net.Interface wants + // one, so we say the interface has broadcast if it has multicast. + sb.append(String.format("%s %d %d %b %b %b %b %b |", nif.getName(), + nif.getIndex(), nif.getMTU(), nif.isUp(), nif.supportsMulticast(), + nif.isLoopback(), nif.isPointToPoint(), nif.supportsMulticast())); + + for (InterfaceAddress ia : nif.getInterfaceAddresses()) { + // InterfaceAddress == hostname + "/" + IP + String[] parts = ia.toString().split("/", 0); + if (parts.length > 1) { + sb.append(String.format("%s/%d ", parts[1], ia.getNetworkPrefixLength())); + } + } + } catch (Exception e) { + // TODO(dgentry) should log the exception not silently suppress it. + continue; + } + sb.append("\n"); + } + + return sb.toString(); + } +} diff --git a/app/src/main/java/com/peernet/test/MainActivity.kt b/app/src/main/java/com/peernet/test/MainActivity.kt index a7ac194..2c3a08b 100644 --- a/app/src/main/java/com/peernet/test/MainActivity.kt +++ b/app/src/main/java/com/peernet/test/MainActivity.kt @@ -1,67 +1,70 @@ package com.peernet.test import android.Manifest -import android.content.ContentValues.TAG import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.database.Cursor +import android.net.ConnectivityManager import android.net.Uri -import android.os.Bundle -import android.view.View -import android.widget.TextView -import androidx.activity.result.contract.ActivityResultContracts -import androidx.appcompat.app.AppCompatActivity -import androidx.core.app.ActivityCompat -import androidx.core.content.ContextCompat -import com.vmadalin.easypermissions.EasyPermissions -import com.vmadalin.easypermissions.annotations.AfterPermissionGranted -import mobile.Mobile -import androidx.core.app.ActivityCompat.requestPermissions - +import android.net.wifi.WifiManager import android.os.Build -import android.provider.Settings +import android.os.Bundle +import android.provider.MediaStore import android.util.Log +import android.view.View import android.widget.Button +import android.widget.TextView +import android.widget.Toast +import androidx.annotation.RequiresApi +import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat.requestPermissions +import androidx.core.content.ContextCompat +import androidx.core.net.toUri import com.android.volley.Request - -import com.android.volley.Request.Method.GET import com.android.volley.Response +import com.android.volley.toolbox.JsonObjectRequest import com.android.volley.toolbox.StringRequest import com.android.volley.toolbox.Volley import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch -import java.io.IOException -import java.util.* -import kotlin.concurrent.schedule -import android.provider.MediaStore -import java.io.File -import android.os.Environment -import com.android.volley.toolbox.JsonObjectRequest -import com.android.volley.toolbox.JsonRequest +import mobile.Mobile import org.json.JSONArray import org.json.JSONObject import org.json.JSONTokener -import android.net.NetworkInfo - -import android.net.ConnectivityManager -import android.os.Handler -import android.widget.Toast -import androidx.annotation.RequiresApi -import androidx.core.net.toFile -import androidx.core.net.toUri import java.nio.file.Files import java.nio.file.Paths +import android.net.wifi.WifiManager.MulticastLock; +import java.util.* +import kotlin.concurrent.schedule class MainActivity : AppCompatActivity() { + private val wifiManager: WifiManager get() = this.applicationContext.getSystemService(Context.WIFI_SERVICE) as WifiManager + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) - Mobile.mobileMain(this.filesDir.absolutePath) + val Interface = GetInterfacesGo.GetInterfacesAsString() + + Log.d("Interface", Interface); + + // See issue #735: Android 11 blocks local discovery if we did not acquire MulticastLock. + // See issue #735: Android 11 blocks local discovery if we did not acquire MulticastLock. + var multicastLock = + wifiManager.createMulticastLock("multicastLock") + multicastLock.setReferenceCounted(true) + multicastLock.acquire() + + + // Start Web Server from the Android side to broadcast + // the information of the network interface +// TinyWebServer.startServer("localhost",9000, "/web/public_html"); + + Mobile.mobileMain(this.filesDir.absolutePath,Interface) if (isNetwork(this)){ @@ -124,7 +127,7 @@ class MainActivity : AppCompatActivity() { numPeers.text = ResponseObject.get("countpeerlist").toString() // connectionLabel.text = response.toString() - // Log.d("myTag", "Response is: ${response.substring(0, 500)}"); + Log.d("myTag", "Response is: ${response}"); }, Response.ErrorListener { errorresponse -> //val connectionLabel = findViewById(R.id.PeernetInfo) as TextView @@ -214,6 +217,11 @@ class MainActivity : AppCompatActivity() { // connectionLabel.text = Mobilecore.mobileCoreStart().toString() // } + if (multicastLock != null) { + multicastLock.release(); + multicastLock = null; + } + } // fun run(url: String) { @@ -244,7 +252,7 @@ class MainActivity : AppCompatActivity() { val path = FileUtils.getPath(this, data?.data) - Log.d("path",path.substring(0, path.lastIndexOf('/'))) + //Log.d("path",path.substring(0, path.lastIndexOf('/'))) // convert Path string to URI val pathUri = path.toUri() diff --git a/app/src/main/java/com/peernet/test/TinyWebServer.java b/app/src/main/java/com/peernet/test/TinyWebServer.java new file mode 100644 index 0000000..9da4205 --- /dev/null +++ b/app/src/main/java/com/peernet/test/TinyWebServer.java @@ -0,0 +1,611 @@ +package com.peernet.test; + +/* + * The MIT License + * + * Copyright 2018 Sonu Auti http://sonuauti.com twitter @SonuAuti + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +import java.io.BufferedWriter; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.lang.reflect.Method; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.URL; +import java.net.URLDecoder; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; +import java.util.regex.Pattern; + +/** + * + * @author Sonu Auti @cis + */ +public class TinyWebServer extends Thread { + + /** + * @param args the command line arguments + */ + private static ServerSocket serverSocket; + private final Map lowerCaseHeader = new HashMap<>(); + + public static String CONTENT_TYPE = "text/html"; + private String CONTENT_DATE = ""; + private String CONN_TYPE = ""; + private String Content_Encoding = ""; + private String content_length = ""; + private String STATUS = "200"; + private boolean keepAlive = true; + private String SERVER_NAME = "Firefly http server v0.1"; + private static final String MULTIPART_FORM_DATA_HEADER = "multipart/form-data"; + private static final String ASCII_ENCODING = "US-ASCII"; + private String REQUEST_TYPE = "GET"; + private String HTTP_VER = "HTTP/1.1"; + + //all status + public static String PAGE_NOT_FOUND = "404"; + public static String OKAY = "200"; + public static String CREATED = "201"; + public static String ACCEPTED = "202"; + public static String NO_CONTENT = "204"; + public static String PARTIAL_NO_CONTENT = "206"; + public static String MULTI_STATUS = "207"; + public static String MOVED_PERMANENTLY = "301"; + public static String SEE_OTHER = "303"; + public static String NOT_MODIFIED = "304"; + public static String TEMP_REDIRECT = "307"; + public static String BAD_REQUEST = "400"; + public static String UNAUTHORIZED_REQUEST = "401"; + public static String FORBIDDEN = "403"; + public static String NOT_FOUND = "404"; + public static String METHOD_NOT_ALLOWED = "405"; + public static String NOT_ACCEPTABLE = "406"; + public static String REQUEST_TIMEOUT = "408"; + public static String CONFLICT = "409"; + public static String GONE = "410"; + public static String LENGTH_REQUIRED = "411"; + public static String PRECONDITION_FAILED = "412"; + + public static String PAYLOAD_TOO_LARGE = "413"; + public static String UNSUPPORTED_MEDIA_TYPE = "415"; + public static String RANGE_NOT_SATISFIABLE = "416"; + public static String EXPECTATION_FAILED = "417"; + public static String TOO_MANY_REQUESTS = "429"; + + public static String INTERNAL_ERROR = "500"; + public static String NOT_IMPLEMENTED = "501"; + public static String SERVICE_UNAVAILABLE = "503"; + public static String UNSUPPORTED_HTTP_VERSION = "505"; + + public static final String CONTENT_DISPOSITION_REGEX = "([ |\t]*Content-Disposition[ |\t]*:)(.*)"; + + public static final Pattern CONTENT_DISPOSITION_PATTERN = Pattern.compile(CONTENT_DISPOSITION_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String CONTENT_TYPE_REGEX = "([ |\t]*content-type[ |\t]*:)(.*)"; + + public static final Pattern CONTENT_TYPE_PATTERN = Pattern.compile(CONTENT_TYPE_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String CONTENT_DISPOSITION_ATTRIBUTE_REGEX = "[ |\t]*([a-zA-Z]*)[ |\t]*=[ |\t]*['|\"]([^\"^']*)['|\"]"; + + public static final Pattern CONTENT_DISPOSITION_ATTRIBUTE_PATTERN = Pattern.compile(CONTENT_DISPOSITION_ATTRIBUTE_REGEX); + + public static final String CONTENT_LENGTH_REGEX = "Content-Length:"; + public static final Pattern CONTENT_LENGTH_PATTERN = Pattern.compile(CONTENT_LENGTH_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String USER_AGENT = "User-Agent:"; + public static final Pattern USER_AGENT_PATTERN = Pattern.compile(USER_AGENT, Pattern.CASE_INSENSITIVE); + + public static final String HOST_REGEX = "Host:"; + public static final Pattern CLIENT_HOST_PATTERN = Pattern.compile(HOST_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String CONNECTION_TYPE_REGEX = "Connection:"; + public static final Pattern CONNECTION_TYPE_PATTERN = Pattern.compile(CONNECTION_TYPE_REGEX, Pattern.CASE_INSENSITIVE); + + public static final String ACCEPT_ENCODING_REGEX = "Accept-Encoding:"; + public static final Pattern ACCEPT_ENCODING_PATTERN = Pattern.compile(ACCEPT_ENCODING_REGEX, Pattern.CASE_INSENSITIVE); + + private static final String CONTENT_REGEX = "[ |\t]*([^/^ ^;^,]+/[^ ^;^,]+)"; + + private static final Pattern MIME_PATTERN = Pattern.compile(CONTENT_REGEX, Pattern.CASE_INSENSITIVE); + + private static final String CHARSET_REGEX = "[ |\t]*(charset)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?"; + + private static final Pattern CHARSET_PATTERN = Pattern.compile(CHARSET_REGEX, Pattern.CASE_INSENSITIVE); + + private static final String BOUNDARY_REGEX = "[ |\t]*(boundary)[ |\t]*=[ |\t]*['|\"]?([^\"^'^;^,]*)['|\"]?"; + + private static final Pattern BOUNDARY_PATTERN = Pattern.compile(BOUNDARY_REGEX, Pattern.CASE_INSENSITIVE); + + + public static String WEB_DIR_PATH="/"; + public static String SERVER_IP="localhost"; + public static int SERVER_PORT=9000; + public static boolean isStart=true; + public static String INDEX_FILE_NAME="index.html"; + + + public TinyWebServer(final String ip, final int port) throws IOException { + + InetAddress addr = InetAddress.getByName(ip); ////"172.31.0.186"); + serverSocket = new ServerSocket(port, 100, addr); + serverSocket.setSoTimeout(5000); //set timeout for listner + + } + + @Override + public void run() { + + while (isStart) { + try { + //wait for new connection on port 5000 + Socket newSocket = serverSocket.accept(); + Thread newClient = new EchoThread(newSocket); + newClient.start(); + } catch (SocketTimeoutException s) { + } catch (IOException e) { + } + + }//endof Never Ending while loop + + } + + public class EchoThread extends Thread { + + protected Socket socket; + protected boolean nb_open; + + public EchoThread(Socket clientSocket) { + this.socket = clientSocket; + this.nb_open = true; + } + + @Override + public void run() { + + try { + DataInputStream in = null; + DataOutputStream out = null; + + if (socket.isConnected()) { + in = new DataInputStream(socket.getInputStream()); + out = new DataOutputStream(socket.getOutputStream()); + } + + byte[] data = new byte[1500]; + //socket.setSoTimeout(60 * 1000 * 5); + + while (in.read(data) != -1) { + String recData = new String(data).trim(); + //System.out.println("received data: \n" + recData); + //System.out.println("------------------------------"); + String[] header = recData.split("\\r?\\n"); + + String contentLen = "0"; + String contentType = "text/html"; + String connectionType = "keep-alive"; + String hostname = ""; + String userAgent = ""; + String encoding = ""; + + String[] h1 = header[0].split(" "); + if (h1.length == 3) { + setRequestType(h1[0]); + setHttpVer(h1[2]); + } + + for (int h = 0; h < header.length; h++) { + String value = header[h].trim(); + + //System.out.println(header[h]+" -> "+CONTENT_LENGTH_PATTERN.matcher(header[h]).find()); + if (CONTENT_LENGTH_PATTERN.matcher(value).find()) { + contentLen = value.split(":")[1].trim(); + } else if (CONTENT_TYPE_PATTERN.matcher(value).find()) { + contentType = value.split(":")[1].trim(); + } else if (CONNECTION_TYPE_PATTERN.matcher(value).find()) { + connectionType = value.split(":")[1].trim(); + } else if (CLIENT_HOST_PATTERN.matcher(value).find()) { + hostname = value.split(":")[1].trim(); + } else if (USER_AGENT_PATTERN.matcher(value).find()) { + for (String ua : value.split(":")) { + if (!ua.equalsIgnoreCase("User-Agent:")) { + userAgent += ua.trim(); + } + } + } else if (ACCEPT_ENCODING_PATTERN.matcher(value).find()) { + encoding = value.split(":")[1].trim(); + } + + } + + if (!REQUEST_TYPE.equals("")) { + String postData = ""; + if (REQUEST_TYPE.equalsIgnoreCase("POST") && !contentLen.equals("0")) { + postData = header[header.length - 1]; + if (postData.length() > 0 && contentLen.length() > 0) { + int len = Integer.valueOf(contentLen); + postData = postData.substring(0, len); + // System.out.println("Post data -> " + contentLen + " ->" + postData); + } + } + + // System.out.println("contentLen ->" + contentLen + "\ncontentType ->" + contentType + "\nhostname ->" + hostname + "\nconnectionType-> " + connectionType + "\nhostname ->" + hostname + "\nuserAgent -> " + userAgent); + final String requestLocation = h1[1]; + if (requestLocation != null) { + processLocation(out, requestLocation, postData); + } + //System.out.println("requestLocation "+requestLocation); + } + + } + } catch (Exception er) { + er.printStackTrace(); + } + + } + + } + + public void processLocation(DataOutputStream out, String location, String postData) { + + String data = ""; + switch (location) { + case "/": + //root location, server index file + CONTENT_TYPE = "text/html"; + data=readFile(WEB_DIR_PATH+"/"+INDEX_FILE_NAME); + constructHeader(out, data.length() + "", data); + break; + default: + + System.out.println("url location -> " + location); + URL geturl = getDecodedUrl("http://localhost" + location); + String[] dirPath = geturl.getPath().split("/"); + String fullFilePath=geturl.getPath(); + if (dirPath.length > 1) { + String fileName = dirPath[dirPath.length - 1]; + HashMap qparms = (HashMap) splitQuery(geturl.getQuery()); + if(REQUEST_TYPE.equals("POST")){ + if (qparms==null){ qparms=new HashMap();} + qparms.put("_POST", postData); + } + //System.out.println("File name " + fileName); + //System.out.println("url parms " + qparms); + CONTENT_TYPE = getContentType(fileName); + if(!CONTENT_TYPE.equals("text/plain")){ + // System.out.println("Full file path - >"+fullFilePath +" "+CONTENT_TYPE); + + if(CONTENT_TYPE.equals("image/jpeg") || CONTENT_TYPE.equals("image/png") || CONTENT_TYPE.equals("video/mp4")){ + byte[] bytdata=readImageFiles(WEB_DIR_PATH+fullFilePath,CONTENT_TYPE); + //System.out.println(bytdata.length); + if(bytdata!=null){ + constructHeaderImage(out, bytdata.length+"", bytdata); + }else{ + pageNotFound(); + } + }else{ + data=readFile(WEB_DIR_PATH+fullFilePath); + if(!data.equals("")){ + constructHeader(out, data.length() + "", data); + }else{ + pageNotFound(); + } + } + }else{ + data = getResultByName(fileName, qparms); + constructHeader(out, data.length() + "", data); + } + + + } + + } + + } + + public URL getDecodedUrl(String parms) { + try { + //String decodedurl =URLDecoder.decode(parms,"UTF-8"); + URL aURL = new URL(parms); + return aURL; + } catch (Exception er) { + } + return null; + } + + public static HashMap splitQuery(String parms) { + try { + final HashMap query_pairs = new HashMap<>(); + final String[] pairs = parms.split("&"); + for (String pair : pairs) { + final int idx = pair.indexOf("="); + final String key = idx > 0 ? URLDecoder.decode(pair.substring(0, idx), "UTF-8") : pair; + if (!query_pairs.containsKey(key)) { + query_pairs.put(key, ""); + } + final String value = idx > 0 && pair.length() > idx + 1 ? URLDecoder.decode(pair.substring(idx + 1), "UTF-8") : null; + query_pairs.put(key, value); + } + return query_pairs; + } catch (Exception er) { + } + return null; + } + + public String getResultByName(String name, HashMap qparms) { + try { + String ClassName = "appapis.queryfiles.AppApis"; + Class rClass = Class.forName(ClassName); // convert string classname to class + Object obj = rClass.newInstance(); // invoke empty constructor + Method getNameMethod = obj.getClass().getMethod(name, HashMap.class); + STATUS = TinyWebServer.OKAY; + return getNameMethod.invoke(obj, qparms).toString(); + } catch (Exception er) { + // er.printStackTrace(); + return pageNotFound(); + } + } + + public void setRequestType(String type) { + // System.out.println("REQUEST TYPE " + type); + this.REQUEST_TYPE = type; + } + + public void setHttpVer(String httpver) { + // System.out.println("REQUEST ver " + httpver); + this.HTTP_VER = httpver; + } + + public String getRequestType() { + return this.REQUEST_TYPE; + } + + public String getHttpVer() { + return this.HTTP_VER; + } + + public String pageNotFound() { + STATUS = NOT_FOUND; + CONTENT_TYPE = "text/html"; + //customize your page here + return "" + + "Page not found | Firefly web server" + + "

Requested page not found

"; + } + + //hashtable initilization for content types + static Hashtable mContentTypes = new Hashtable(); + + { + mContentTypes.put("js", "application/javascript"); + mContentTypes.put("php", "text/html"); + mContentTypes.put("java", "text/html"); + mContentTypes.put("json", "application/json"); + mContentTypes.put("png", "image/png"); + mContentTypes.put("jpg", "image/jpeg"); + mContentTypes.put("html", "text/html"); + mContentTypes.put("css", "text/css"); + mContentTypes.put("mp4", "video/mp4"); + mContentTypes.put("mov", "video/quicktime"); + mContentTypes.put("wmv", "video/x-ms-wmv"); + + } + + //get request content type + public static String getContentType(String path) { + String type = tryGetContentType(path); + if (type != null) { + return type; + } + return "text/plain"; + } + + //get request content type from path + public static String tryGetContentType(String path) { + int index = path.lastIndexOf("."); + if (index != -1) { + String e = path.substring(index + 1); + String ct = mContentTypes.get(e); + // System.out.println("content type: " + ct); + if (ct != null) { + return ct; + } + } + return null; + } + + private void constructHeader(DataOutputStream output, String size, String data) { + SimpleDateFormat gmtFrmt = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); + gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); + PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output)), false); + pw.append("HTTP/1.1 ").append(STATUS).append(" \r\n"); + if (this.CONTENT_TYPE != null) { + printHeader(pw, "Content-Type", this.CONTENT_TYPE); + } + printHeader(pw, "Date", gmtFrmt.format(new Date())); + printHeader(pw, "Connection", (this.keepAlive ? "keep-alive" : "close")); + printHeader(pw, "Content-Length", size); + printHeader(pw, "Server", SERVER_NAME); + pw.append("\r\n"); + pw.append(data); + pw.flush(); + //pw.close(); + } + + private void constructHeaderImage(DataOutputStream output, String size, byte[] data) { + try{ + + SimpleDateFormat gmtFrmt = new SimpleDateFormat("E, d MMM yyyy HH:mm:ss 'GMT'", Locale.US); + gmtFrmt.setTimeZone(TimeZone.getTimeZone("GMT")); + PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output)), false); + pw.append("HTTP/1.1 ").append(STATUS).append(" \r\n"); + if (this.CONTENT_TYPE != null) { + printHeader(pw, "Content-Type", this.CONTENT_TYPE); + } + printHeader(pw, "Date", gmtFrmt.format(new Date())); + printHeader(pw, "Connection", (this.keepAlive ? "keep-alive" : "close")); + printHeader(pw, "Content-Length", size); + printHeader(pw, "Server", SERVER_NAME); + pw.append("\r\n"); + pw.flush(); + output.write(data); + output.flush(); + //System.out.println("data sent success"); + + //pw.close(); + }catch(Exception er){er.printStackTrace();} + + } + + + @SuppressWarnings("static-method") + protected void printHeader(PrintWriter pw, String key, String value) { + pw.append(key).append(": ").append(value).append("\r\n"); + } + + public byte[] readImageFiles(String fileName,String filetype){ + try{ + File ifile=new File(fileName); + if(ifile.exists()){ + if(filetype.equalsIgnoreCase("image/png") || filetype.equalsIgnoreCase("image/jpeg") || filetype.equalsIgnoreCase("image/gif") || filetype.equalsIgnoreCase("image/jpg")){ + FileInputStream fis = new FileInputStream(fileName); + byte[] buffer = new byte[fis.available()]; + while (fis.read(buffer) != -1) {} + fis.close(); + return buffer; + } + }else{ + + } + }catch(Exception er){} + return null; + } + public String readFile(String fileName){ + String content=""; + try{ + File ifile=new File(fileName); + if(ifile.exists()){ + FileInputStream fis = new FileInputStream(fileName); + byte[] buffer = new byte[10]; + StringBuilder sb = new StringBuilder(); + while (fis.read(buffer) != -1) { + sb.append(new String(buffer)); + buffer = new byte[10]; + } + fis.close(); + content = sb.toString(); + }else{ + pageNotFound(); + return content; + } + }catch(Exception er){ + pageNotFound(); + return ""; + } + return content; + } + + + public static void init(String ip,int port,String public_dir){ + + SERVER_IP=ip; + SERVER_PORT=port; + WEB_DIR_PATH=public_dir; + scanFileDirectory(); + + } + + public static void startServer(String ip,int port,String public_dir){ + try { + + isStart=true; + init(ip,port,public_dir); + Thread t = new TinyWebServer(SERVER_IP, SERVER_PORT); + t.start(); + System.out.println("Server Started !"); + + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + } + } + + public static void stopServer(){ + if(isStart){ + try{ + isStart=false; + serverSocket.close(); + System.out.println("Server stopped running !"); + }catch(IOException er){ + er.printStackTrace(); + } + } + } + + + //scan for index file + public static void scanFileDirectory(){ + boolean isIndexFound=false; + try{ + File file=new File(WEB_DIR_PATH); + if(file.isDirectory()){ + File[] allFiles=file.listFiles(); + for (File allFile : allFiles) { + //System.out.println(allFile.getName().split("\\.")[0]); + if(allFile.getName().split("\\.")[0].equalsIgnoreCase("index")){ + TinyWebServer.INDEX_FILE_NAME=allFile.getName(); + isIndexFound=true; + } + } + } + + }catch(Exception er){} + + if(!isIndexFound){ + System.out.println("Index file not found !"); + } + } + + /* //use for testing + public static void main(String[] args) { + try { + Thread t = new TinyWebServer(SERVER_IP, SERVER_PORT); + t.start(); + System.out.println("Server Started !"); + } catch (IOException e) { + e.printStackTrace(); + } catch (Exception e) { + } + }*/ + +}