simple web server added

This commit is contained in:
simon 2020-08-19 17:00:08 +03:00
parent 51786f71f0
commit e024953ebe
8 changed files with 1113 additions and 0 deletions

View file

@ -408,6 +408,7 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<activity android:name="androidhttpweb.ServerActivity" android:label="@string/shared_string_settings" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.activities.SettingsActivity" android:label="@string/shared_string_settings" android:configChanges="keyboardHidden|orientation" /> <activity android:name="net.osmand.plus.activities.SettingsActivity" android:label="@string/shared_string_settings" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.activities.SettingsGeneralActivity" android:configChanges="keyboardHidden|orientation" /> <activity android:name="net.osmand.plus.activities.SettingsGeneralActivity" android:configChanges="keyboardHidden|orientation" />
<activity android:name="net.osmand.plus.activities.SettingsNavigationActivity" android:configChanges="keyboardHidden|orientation" /> <activity android:name="net.osmand.plus.activities.SettingsNavigationActivity" android:configChanges="keyboardHidden|orientation" />

View file

@ -0,0 +1,238 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>BootsApp | Home</title>
<style>
</style>
</head>
<body>
<a onclick="window.location.href = '/button1Click';">
<button style="text-align: center;" class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
CLICK ME TO SHOW TOAST
</button>
</a>
<nav class="navbar navbar-expand-md bg-secondary navbar-dark fixed-top shadow">
<a class="navbar-brand" href="#">LOGO </a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsibleNavbar">
<ul class="nav navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link active" href="#"><i class="fas fa-home fa-lg d-md-none pr-2 "></i>Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="about.html"><i class="fas fa-info-circle fa-lg d-md-none pr-2"></i> About</a>
</li>
<li class="nav-item">
<a class="nav-link" href="pricing.html"><i class="fas fa-rupee-sign fa-2x d-md-none pr-2"></i> Pricing</a>
</li>
<li class="nav-item">
<a class="nav-link" href="login.html"><i class="fas fa-user fa-lg d-md-none pr-2"></i> Login</a>
</li>
<li class="nav-item">
<a class="nav-link" href="signup.html"><i class="fas fa-edit fa-lg d-md-none pr-2"></i>Signup</a>
</li>
</ul>
</div>
</nav>
<div class="container header">
<div class="jumbotron">
<div class="header-content mt-4">
<h2 class="display-2">Company Inc.</h2>
<p>Lorem ipsum, dolor sit amet consectetur adipisicing elit. Ut unde quaerat consequatur?</p>
<a href="login.html" class="btn btn-primary">Get Started</a>
</div>
</div>
</div>
<div class="container features">
<h2 class="text-center mb-4">Our Speciality</h2>
<div class="row">
<div class="col-md-4 col-sm-12 p-2 shadow-sm text-center spec">
<i class="fas fa-tablet-alt fa-2x mb-2"></i>
<h4>Device Compatible</h4>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, doloremque voluptatum. Ducimus.</p>
</div>
<div class="col-md-4 col-sm-12 shadow-sm text-center spec">
<i class="fas fa-cloud fa-2x mb-2"></i>
<h4>Cloud Support</h4>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, doloremque voluptatum. Ducimus.</p>
</div>
<div class="col-md-4 col-sm-12 shadow-sm text-center spec">
<i class="fas fa-phone fa-2x mb-2"></i>
<h4>24/7 Call Support</h4>
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Illo, doloremque voluptatum. Ducimus.</p>
</div>
</div>
</div>
<div class="container products">
<h2 class="text-center mb-4">Our Products</h2>
<div class="row mt-4 p-4">
<div class="col-md-5 col-sm-12">
<img src="https://images.unsplash.com/photo-1501959181532-7d2a3c064642?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=9ffb47d2c8a236bae5e5bb86b2c400b9&auto=format&fit=crop&w=1070&q=80" style="height: 100%;width: 100%;" alt="product-image" class="shadow-lg">
</div>
<div class="col-md-7 col-sm-12 mt-sm-4" style="display:flex;align-items:center;">
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitatibus esse alias expedita quia doloremque assumenda. Cupiditate nam exercitationem voluptatem quidem ad dolore ullam aliquid culpa ducimus qui, ut dignissimos inventore veniam!</p>
</div>
</div>
<div class="row mt-4 p-4 hide-on-sm">
<div class="col-md-7 col-sm-12 mt-sm-4" style="display:flex;align-items:center;">
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitatibus esse alias expedita quia doloremque assumenda. Cupiditate nam exercitationem voluptatem !</p>
</div>
<div class="col-md-5 col-sm-12">
<img src="https://images.unsplash.com/photo-1517694712202-14dd9538aa97?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=a20bc6324f6ef2969d9a7cae56b8d4d1&auto=format&fit=crop&w=1050&q=80" style="height: 100%;width: 100%;" alt="product-image" class="shadow-lg">
</div>
</div>
<div class="row mt-4 p-4">
<div class="col-md-5 col-sm-12">
<img src="https://images.unsplash.com/photo-1512486130939-2c4f79935e4f?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=dfd2ec5a01006fd8c4d7592a381d3776&auto=format&fit=crop&w=800&q=80" style="height: 100%;width: 100%;" alt="product-image" class="shadow-lg">
</div>
<div class="col-md-7 col-sm-12 mt-sm-4" style="display:flex;align-items:center;">
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitatibus esse alias expedita quia doloremque assumenda. Cupiditate nam exercitationem voluptatem quidem ad dolore ullam aliquid culpa ducimus qui, ut dignissimos inventore veniam!</p>
</div>
</div>
<div class="text-center"><a href="#" class="btn btn-default text-center">View more</a></div>
</div>
<div class="container">
<h2 class="text-center mb-4">Our Customers</h2>
<div id="carousel" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
<li data-target="#carousel" data-slide-to="0" class="active"></li>
<li data-target="#carousel" data-slide-to="1"></li>
<li data-target="#carousel" data-slide-to="2"></li>
</ol>
<div class="carousel-inner" role="listbox">
<div class="carousel-item active">
<div class="row mt-4 p-4">
<div class="col-md-5 col-xs-12 mt-sm-2">
<img src="https://images.unsplash.com/photo-1497215842964-222b430dc094?ixlib=rb-0.3.5&s=76fbdf2a268252eb9d7c7dbd55f445dc&auto=format&fit=crop&w=1050&q=80" style="height: 100%;width: 100%;" alt="product-image">
</div>
<div class="col-md-7 col-xs-12" style="display:flex;align-items:center;">
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit.nam exercitationem voluptatem quidem ad dolore ullam aliquid culpa ducimus qui, ut dignissimos inventore veniam!<br>
<cite class="small">~ George Henry, <span class="text-muted">Lead Engineer Fast Labs</span></cite></p>
</div>
</div>
</div>
<div class="carousel-item">
<div class="row mt-4 p-4">
<div class="col-md-5 col-xs-12">
<img src="https://images.unsplash.com/photo-1434626982825-b030fb94f5be?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=862c021c4fa3b0255cc666fafc5dbfdc&auto=format&fit=crop&w=1053&q=80" style="height: 100%;width: 100%;" alt="product-image">
</div>
<div class="col-md-7 col-xs-12 mt-sm-2" style="display:flex;align-items:center;">
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitati fafe gnissimos inventore veniam!<br>
<cite class="small">~ John Anderson, <span class="text-muted">CTO Acme Tech.</span></cite></p>
<!-- <blockquote class="blockquote text-left">
<p class="mb-0">Lorem ipsum dolor sit amet consectetur adipisicing elit. Ea magnam, possimus sed ex deleniti facere? Quidem dignissimos blanditiis ut sequi accusantium necessitatibus. Aperiam?</p>
<footer class="blockquote-footer"> <cite title="Source Title">Source Title</cite></footer>
</blockquote> -->
</div>
</div>
</div>
<div class="carousel-item">
<div class="row mt-4 p-4">
<div class="col-md-5 col-xs-12">
<img src="https://images.unsplash.com/photo-1525332193053-dee9e7348624?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=a171c64a1cb121a923c4e95d8308ca9e&auto=format&fit=crop&w=1050&q=80" style="max-height: 100%;max-width: 100%;" alt="product-image">
</div>
<div class="col-md-7 col-xs-12 mt-sm-2" style="display:flex;align-items:center;">
<p class="lead">Lorem ipsum dolor sit, amet consectetur adipisicing elit. Velit nobis officiis unde necessitatibus esmos inventore veniam!<br>
<cite class="small">~ Ishaan Sheikh, <span class="text-muted">CEO Sigma Inc.</span></cite></p>
</div>
</div>
</div>
</div>
<a class="carousel-control-prev" href="#carousel" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carousel" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
<div class="container-fluid bg-primary p-4 mt-4 last-sec">
<div class="text-center">
<h2 class="display-4 text-white">Ready to get started</h2>
<a href="login.html" class="btn btn-dark btn-lg mt-2">Try it for free</a><br>
</div>
</div>
<!-- <div style="height: 500px;"></div> -->
<div class="container-fluid bg-dark text-white pb-4">
<div class="row p-4">
<div class="col-md-4 col-sm-12 text-center">
<ul class="list-unstyled">
<li class="list-header" style="font-size: 1.5rem;">Developer</li>
<li><div class="divider bg-light" ></div></li>
<li><a href="#" class="btn text-white">Developer's API</a></li>
<li><a href="#" class="btn text-white">Get Your API key</a></li>
<li><a href="#" class="btn text-white">OAuth Key</a></li>
<li><a href="#" class="btn text-white">Pricing</a></li>
</ul>
</div>
<div class="col-md-4 col-sm-12 text-center">
<ul class="list-unstyled ">
<li class="list-header" style="font-size: 1.5rem;">Support</li>
<li><div class="divider bg-light" ></div></li>
<li><a href="#" class="btn text-white">Troubleshoot</a></li>
<li><a href="#" class="btn text-white">Questions</a></li>
<li><a href="#" class="btn text-white">Report a bug</a></li>
<li><a href="#" class="btn text-white">Help</a></li>
</ul>
</div>
<div class="col-md-4 col-sm-12 text-center">
Follow us on
<ul class="list-unstyled list-inline social-icons mt-1">
<li class="list-inline-item"><a href="#"><i class="fab fa-2x fa-facebook-square"></i></a> </li>
<li class="list-inline-item"><a href="#"><i class="fab fa-2x fa-google"></i></a> </li>
<li class="list-inline-item"><a href="#"><i class="fab fa-2x fa-twitter-square"></i></a> </li>
<li class="list-inline-item"><a href="#"><i class="fab fa-2x fa-instagram"></i></a> </li>
<li class="list-inline-item"><a href="#"><i class="fab fa-medium fa-2x"></i></a></li>
</ul>
</div>
</div>
<div class="text-center">
<span class="fas fa-code text-primary"></span>&nbsp;&nbsp;with&nbsp;&nbsp;<span class="fas fa-heart" style="color: red"></span> By Developers<br>
2018 &copy; Developers.com<br>
The images are taken from <a href="https://unsplash.com">Unsplash.com</a> to avoid copyright issues.
</div>
</div>
<script>
// window.sr = ScrollReveal();
// sr.reveal('h2.display-2',{
// duration:2000,
// origin:'left',
// distance:'30px'
// });
// sr.reveal('',{
// duration:2000,
// origin:'left',
// distance:'30px'
// });
</script>
</body>
</html>

View file

@ -0,0 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:padding="10px">
<RelativeLayout
android:id="@+id/RelativeLayout03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="20px"
android:layout_marginBottom="40px">
<TextView
android:id="@+id/TextView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:autoLink="web"
android:text="Click button to start server"></TextView>
</RelativeLayout>
<Button
android:id="@+id/Button01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/RelativeLayout03"
android:layout_alignParentLeft="true"
android:layout_marginBottom="40px"
android:text="Start"></Button>
<Button
android:id="@+id/Button03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/Button01"
android:layout_alignParentRight="true"
android:layout_alignParentLeft="true"
android:text="Stop"></Button>
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/Button03"
android:fitsSystemWindows="true"
android:lines="14"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textSize="8dp" />
</RelativeLayout>

View file

@ -11,6 +11,7 @@
Thx - Hardy Thx - Hardy
--> -->
<string name="web_server">Web server</string>
<string name="in_case_of_reverse_direction">In case of reverse direction</string> <string name="in_case_of_reverse_direction">In case of reverse direction</string>
<string name="plan_route_exit_dialog_descr">Are you sure you want to close Plan route without saving? You will lose all changes.</string> <string name="plan_route_exit_dialog_descr">Are you sure you want to close Plan route without saving? You will lose all changes.</string>
<string name="street_level_imagery">Street-level imagery</string> <string name="street_level_imagery">Street-level imagery</string>

View file

@ -0,0 +1,59 @@
package androidhttpweb;
import android.net.TrafficStats;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import net.osmand.plus.R;
public class ServerActivity extends AppCompatActivity {
private boolean initialized = false;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.server_activity);
findViewById(R.id.Button01).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!initialized) {
((TextView) findViewById(R.id.TextView02)).setText("Click second button to deactivate server");
initServer();
}
}
});
findViewById(R.id.Button03).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (initialized) {
((TextView) findViewById(R.id.TextView02)).setText("Click first button to activate server");
deInitServer();
}
}
});
}
private void initServer() {
final String ip = "localhost";
final int port = 9000;
final int THREAD_ID = 10000;
TrafficStats.setThreadStatsTag(THREAD_ID);
TinyWebServer.startServer(ip, port, "/web/public_html");
TinyWebServer.object = ServerActivity.this;
}
private void deInitServer() {
TinyWebServer.stopServer();
initialized = false;
}
@Override
protected void onDestroy() {
deInitServer();
super.onDestroy();
}
}

View file

@ -0,0 +1,614 @@
/*
* 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.
*/
package androidhttpweb;
import android.net.TrafficStats;
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<String, String> 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 static Object object;
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 {
TrafficStats.setThreadStatsTag(1);
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<String, String>();}
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<String, String> splitQuery(String parms) {
try {
final HashMap<String, String> 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 "<!DOCTYPE html>"
+ "<html><head><title>Page not found | Firefly web server</title>"
+ "</head><body><h3>Requested page not found</h3></body></html>";
}
//hashtable initilization for content types
static Hashtable<String, String> 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) {
}
}*/
}

View file

@ -0,0 +1,134 @@
/*
* 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.
*/
package appapis.queryfiles;
import android.widget.Toast;
import org.apache.commons.compress.utils.IOUtils;
import androidhttpweb.ServerActivity;
import androidhttpweb.TinyWebServer;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Scanner;
/**
*
* @author cis
*/
public class AppApis {
public AppApis(){
}
public String helloworld(HashMap qparms){
//demo of simple html webpage from controller method
TinyWebServer.CONTENT_TYPE="text/html";
return "<html><head><title>Simple HTML and Javascript Demo</title>\n" +
" <script>\n" +
" \n" +
"</script>\n" +
" \n" +
" </head><body style=\"text-align:center;margin-top: 5%;\" cz-shortcut-listen=\"true\" class=\"\">\n" +
" <h3>Say Hello !</h3>\n" +
"<div style=\"text-align:center;margin-left: 29%;\">\n" +
"<div id=\"c1\" style=\"width: 100px;height: 100px;color: gray;background: gray;border-radius: 50%;float: left;\"></div>\n" +
"<div id=\"c2\" style=\"width: 100px;height: 100px;color: gray;background: yellow;border-radius: 50%;float: left;\"></div>\n" +
"<div id=\"c3\" style=\"width: 100px;height: 100px;color: gray;background: skyblue;border-radius: 50%;float: left;\"></div>\n" +
"<div id=\"c4\" style=\"width: 100px;height: 100px;color: gray;background: yellowgreen;border-radius: 50%;float: left;\"></div>\n" +
"<div id=\"c5\" style=\"width: 100px;height: 100px;color: gray;background: red;border-radius: 50%;position: ;position: ;float: left;\" class=\"\"></div></div>\n" +
" </body></html>";
}
public String simplejson(HashMap qparms){
//simple json output demo from controller method
String json = "{\"name\":\"sonu\",\"age\":29}";
return json.toString();
}
public String simplegetparm(HashMap qparms){
/*
qparms is hashmap of get and post parameter
simply use qparms.get(key) to get parameter value
user _POST as key for post data
e.g to get post data use qparms.get("_POST"), return will be post method
data
*/
System.out.println("output in simplehelloworld "+qparms);
String p="";
if(qparms!=null){
p=qparms.get("age")+"";
}
String json = "{\"name\":\"sonu\",\"age\":"+p+",\"isp\":yes}";
return json.toString();
}
public String main(HashMap qparams){
TinyWebServer.CONTENT_TYPE="text/html";
final ServerActivity act = ((ServerActivity)(TinyWebServer.object));
InputStream stream = null;
try {
stream = act.getAssets().open("server/main.html");
} catch (IOException e) {
e.printStackTrace();
}
Scanner s = new Scanner(stream).useDelimiter("\\A");
String result = s.hasNext() ? s.next() : "";
return result;
}
public String button1Click(HashMap qparams){
try {
final ServerActivity act = ((ServerActivity)(TinyWebServer.object));
act.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(act,"Hello from btn1",Toast.LENGTH_LONG).show();
}
});
}
catch (Exception e){
e.printStackTrace();
}
TinyWebServer.CONTENT_TYPE="text/html";
return "<script>\n" +
"function goBack() {\n" +
" window.history.back()\n" +
"}\n" +
"goBack();" +
"</script>";
}
public String button2Click(HashMap qparams){
return "cancel";
}
//implement web callback here and access them using method name
}

View file

@ -36,6 +36,7 @@ import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox; import net.osmand.data.RotatedTileBox;
import net.osmand.map.ITileSource; import net.osmand.map.ITileSource;
import net.osmand.plus.dialogs.SpeedCamerasBottomSheet; import net.osmand.plus.dialogs.SpeedCamerasBottomSheet;
import androidhttpweb.ServerActivity;
import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.ContextMenuAdapter; import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuAdapter.ItemClickListener; import net.osmand.plus.ContextMenuAdapter.ItemClickListener;
@ -1011,6 +1012,20 @@ public class MapActivityActions implements DialogProvider {
}).createItem()); }).createItem());
*/ */
optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.web_server, mapActivity)
.setId("SERVER_ID")
.setIcon(R.drawable.mm_shop_computer)
.setListener(new ItemClickListener() {
@Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, int itemId, int pos, boolean isChecked, int[] viewCoordinates) {
app.logEvent("drawer_help_open");
Intent intent = new Intent(mapActivity, ServerActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
mapActivity.startActivity(intent);
return true;
}
}).createItem());
optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.shared_string_help, mapActivity) optionsMenuHelper.addItem(new ItemBuilder().setTitleId(R.string.shared_string_help, mapActivity)
.setId(DRAWER_HELP_ID) .setId(DRAWER_HELP_ID)
.setIcon(R.drawable.ic_action_help) .setIcon(R.drawable.ic_action_help)