├── base
├── .gitignore
├── src
│ └── main
│ │ ├── res
│ │ └── drawable
│ │ │ ├── offline.png
│ │ │ └── online.png
│ │ ├── AndroidManifest.xml
│ │ └── java
│ │ └── ro
│ │ └── polak
│ │ └── webserver
│ │ └── base
│ │ ├── ConfigurationException.java
│ │ ├── impl
│ │ └── AndroidCliServerGui.java
│ │ └── logic
│ │ └── AssetUtil.java
└── build.gradle
├── cli
├── .gitignore
└── build.gradle
├── http
├── .gitignore
├── src
│ ├── main
│ │ └── java
│ │ │ ├── ro
│ │ │ └── polak
│ │ │ │ └── http
│ │ │ │ ├── exception
│ │ │ │ ├── AccessDeniedException.java
│ │ │ │ ├── MethodNotAllowedException.java
│ │ │ │ ├── FilterInitializationException.java
│ │ │ │ ├── ServletInitializationException.java
│ │ │ │ ├── protocol
│ │ │ │ │ ├── UnsupportedProtocolException.java
│ │ │ │ │ ├── UriTooLongProtocolException.java
│ │ │ │ │ ├── LengthRequiredException.java
│ │ │ │ │ ├── PayloadTooLargeProtocolException.java
│ │ │ │ │ ├── MalformedStatusLineException.java
│ │ │ │ │ ├── StatusLineTooLongProtocolException.java
│ │ │ │ │ ├── RangeNotSatisfiableProtocolException.java
│ │ │ │ │ ├── MalformedOrUnsupportedMethodProtocolException.java
│ │ │ │ │ └── ProtocolException.java
│ │ │ │ ├── NotFoundException.java
│ │ │ │ ├── ServletException.java
│ │ │ │ └── UnexpectedSituationException.java
│ │ │ │ ├── protocol
│ │ │ │ ├── parser
│ │ │ │ │ ├── MalformedInputException.java
│ │ │ │ │ ├── Parser.java
│ │ │ │ │ └── impl
│ │ │ │ │ │ ├── QueryStringParser.java
│ │ │ │ │ │ ├── CookieParser.java
│ │ │ │ │ │ ├── RequestStatusParser.java
│ │ │ │ │ │ └── RangeParser.java
│ │ │ │ └── serializer
│ │ │ │ │ ├── Serializer.java
│ │ │ │ │ └── impl
│ │ │ │ │ └── HeadersSerializer.java
│ │ │ │ ├── servlet
│ │ │ │ ├── ServletOutputStream.java
│ │ │ │ ├── ServletConfig.java
│ │ │ │ ├── FilterConfig.java
│ │ │ │ ├── BasicAbstractFilter.java
│ │ │ │ ├── Range.java
│ │ │ │ ├── FilterChain.java
│ │ │ │ ├── impl
│ │ │ │ │ ├── FilterConfigImpl.java
│ │ │ │ │ ├── ServletConfigImpl.java
│ │ │ │ │ └── FilterChainImpl.java
│ │ │ │ ├── ServletPrintWriter.java
│ │ │ │ ├── Filter.java
│ │ │ │ ├── Servlet.java
│ │ │ │ ├── ServletContainer.java
│ │ │ │ ├── HttpServlet.java
│ │ │ │ ├── ChunkedPrintWriter.java
│ │ │ │ ├── helper
│ │ │ │ │ └── RangeHelper.java
│ │ │ │ ├── UploadedFile.java
│ │ │ │ ├── ServletContext.java
│ │ │ │ └── factory
│ │ │ │ │ └── HttpServletResponseImplFactory.java
│ │ │ │ ├── errorhandler
│ │ │ │ ├── HttpErrorHandlerResolver.java
│ │ │ │ ├── impl
│ │ │ │ │ ├── HttpError400Handler.java
│ │ │ │ │ ├── HttpError414Handler.java
│ │ │ │ │ ├── HttpError411Handler.java
│ │ │ │ │ ├── HttpError413Handler.java
│ │ │ │ │ ├── HttpError416Handler.java
│ │ │ │ │ ├── HttpError503Handler.java
│ │ │ │ │ ├── HttpError505Handler.java
│ │ │ │ │ ├── HttpError403Handler.java
│ │ │ │ │ ├── HttpError404Handler.java
│ │ │ │ │ ├── HttpError405Handler.java
│ │ │ │ │ └── HttpError500Handler.java
│ │ │ │ ├── HttpErrorHandler.java
│ │ │ │ └── AbstractPlainTextHttpErrorHandler.java
│ │ │ │ ├── configuration
│ │ │ │ ├── ServerConfigFactory.java
│ │ │ │ ├── ServletMapping.java
│ │ │ │ ├── FilterMapping.java
│ │ │ │ ├── impl
│ │ │ │ │ ├── ServletMappingImpl.java
│ │ │ │ │ └── FilterMappingImpl.java
│ │ │ │ ├── ServletMappingBuilder.java
│ │ │ │ ├── FilterMappingBuilder.java
│ │ │ │ ├── DeploymentDescriptorBuilder.java
│ │ │ │ └── ServerConfig.java
│ │ │ │ ├── gui
│ │ │ │ └── ServerGui.java
│ │ │ │ ├── utilities
│ │ │ │ ├── DateProvider.java
│ │ │ │ ├── DateUtilities.java
│ │ │ │ └── IOUtilities.java
│ │ │ │ ├── MimeTypeMapping.java
│ │ │ │ ├── resource
│ │ │ │ └── provider
│ │ │ │ │ └── ResourceProvider.java
│ │ │ │ ├── controller
│ │ │ │ └── Controller.java
│ │ │ │ ├── Loadable.java
│ │ │ │ ├── PathHelper.java
│ │ │ │ ├── session
│ │ │ │ └── storage
│ │ │ │ │ └── SessionStorage.java
│ │ │ │ ├── RangePartHeader.java
│ │ │ │ ├── MultipartHeadersPart.java
│ │ │ │ ├── ServiceUnavailableHandler.java
│ │ │ │ ├── RequestStatus.java
│ │ │ │ └── impl
│ │ │ │ └── ServletOutputStreamImpl.java
│ │ │ └── example
│ │ │ ├── NotFoundServlet.java
│ │ │ ├── ForbiddenServlet.java
│ │ │ ├── InternalServerErrorServlet.java
│ │ │ ├── ForbiddenByFilterServlet.java
│ │ │ ├── filter
│ │ │ └── FakeSecuredAbstractFilter.java
│ │ │ ├── ChunkedServlet.java
│ │ │ ├── StreamingServlet.java
│ │ │ ├── ChunkedWithDelayServlet.java
│ │ │ ├── CookiesServlet.java
│ │ │ ├── SessionServlet.java
│ │ │ └── FileUploadServlet.java
│ └── test
│ │ └── java
│ │ └── ro
│ │ └── polak
│ │ └── http
│ │ ├── OsUtils.java
│ │ ├── utilities
│ │ ├── DateProviderTest.java
│ │ ├── DateUtilitiesTest.java
│ │ ├── StringUtilitiesTest.java
│ │ ├── FileUtilitiesTest.java
│ │ └── IOUtilitiesTest.java
│ │ ├── servlet
│ │ ├── impl
│ │ │ ├── ServletConfigImplTest.java
│ │ │ ├── HttpServletResponseImplIT.java
│ │ │ └── HttpServletResponseImplTest.java
│ │ ├── loader
│ │ │ ├── SampleFilter.java
│ │ │ └── SampleServlet.java
│ │ ├── ServletPrintWriterTest.java
│ │ ├── HttpServletTest.java
│ │ ├── ChunkedPrintWriterTest.java
│ │ └── CookieTest.java
│ │ ├── controller
│ │ └── impl
│ │ │ └── LoggingUncaughtExceptionHandlerTest.java
│ │ ├── errorhandler
│ │ └── impl
│ │ │ └── HttpErrorHandlerResolverImplTest.java
│ │ ├── exception
│ │ ├── ServletExceptionTest.java
│ │ └── UnexpectedSituationExceptionTest.java
│ │ ├── PathHelperTest.java
│ │ ├── ServerRunnableTest.java
│ │ ├── protocol
│ │ ├── serializer
│ │ │ └── impl
│ │ │ │ └── HeadersSerializerTest.java
│ │ └── parser
│ │ │ └── impl
│ │ │ ├── RequestStatusParserTest.java
│ │ │ ├── CookieParserTest.java
│ │ │ └── QueryStringParserTest.java
│ │ ├── FileUtils.java
│ │ ├── RequestBuilder.java
│ │ ├── HeadersTest.java
│ │ ├── impl
│ │ └── MimeTypeMappingImplTest.java
│ │ └── ServiceUnavailableHandlerTest.java
└── build.gradle
├── screens
├── main.png
├── admin-login.png
├── admin-menu.png
├── admin-sms-inbox.png
├── admin-drive-access.png
├── error-500-stacktrace.png
├── admin-server-statistics.png
└── command-line-interface.png
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── Procfile
├── app
├── src
│ └── main
│ │ ├── res
│ │ ├── drawable
│ │ │ ├── online.png
│ │ │ └── offline.png
│ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ ├── values
│ │ │ ├── styles.xml
│ │ │ ├── dimens.xml
│ │ │ └── strings.xml
│ │ ├── menu
│ │ │ └── menu_main.xml
│ │ └── values-w820dp
│ │ │ └── dimens.xml
│ │ ├── assets
│ │ ├── public
│ │ │ ├── favicon.ico
│ │ │ └── assets
│ │ │ │ ├── img
│ │ │ │ ├── gif.png
│ │ │ │ ├── home.png
│ │ │ │ ├── jpg.png
│ │ │ │ ├── pdf.png
│ │ │ │ ├── png.png
│ │ │ │ ├── zip.png
│ │ │ │ ├── folder.png
│ │ │ │ └── default.png
│ │ │ │ ├── fonts
│ │ │ │ ├── glyphicons-halflings-regular.eot
│ │ │ │ ├── glyphicons-halflings-regular.ttf
│ │ │ │ ├── glyphicons-halflings-regular.woff
│ │ │ │ └── glyphicons-halflings-regular.woff2
│ │ │ │ └── css
│ │ │ │ └── styles.css
│ │ └── conf
│ │ │ └── httpd.properties
│ │ ├── java
│ │ ├── admin
│ │ │ ├── LogoutServlet.java
│ │ │ ├── logic
│ │ │ │ ├── FileIconMapper.java
│ │ │ │ └── AccessControl.java
│ │ │ ├── filter
│ │ │ │ ├── LogoutFilter.java
│ │ │ │ └── SecurityFilter.java
│ │ │ ├── IndexServlet.java
│ │ │ └── ServerStatsServlet.java
│ │ ├── ro
│ │ │ └── polak
│ │ │ │ └── webserver
│ │ │ │ └── MainService.java
│ │ └── api
│ │ │ └── logic
│ │ │ ├── MessageDTOMapper.java
│ │ │ └── APIResponse.java
│ │ └── AndroidManifest.xml
└── build.gradle
├── settings.gradle
├── .gitignore
├── installsdk.sh
├── .gitattributes
└── .github
└── workflows
├── on_pr.yaml
└── on_master.yaml
/base/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/cli/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/http/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/screens/main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/main.png
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | android.enableJetifier=true
3 | android.useAndroidX=true
--------------------------------------------------------------------------------
/screens/admin-login.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/admin-login.png
--------------------------------------------------------------------------------
/screens/admin-menu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/admin-menu.png
--------------------------------------------------------------------------------
/screens/admin-sms-inbox.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/admin-sms-inbox.png
--------------------------------------------------------------------------------
/screens/admin-drive-access.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/admin-drive-access.png
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/screens/error-500-stacktrace.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/error-500-stacktrace.png
--------------------------------------------------------------------------------
/Procfile:
--------------------------------------------------------------------------------
1 | web: mkdir ./httpd/ && echo "server.port=$PORT" >> ./httpd/httpd.properties && java $JAVA_OPTS -jar ./cli/build/libs/cli-all.jar
--------------------------------------------------------------------------------
/app/src/main/res/drawable/online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/res/drawable/online.png
--------------------------------------------------------------------------------
/screens/admin-server-statistics.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/admin-server-statistics.png
--------------------------------------------------------------------------------
/screens/command-line-interface.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/screens/command-line-interface.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/favicon.ico
--------------------------------------------------------------------------------
/app/src/main/res/drawable/offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/res/drawable/offline.png
--------------------------------------------------------------------------------
/base/src/main/res/drawable/offline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/base/src/main/res/drawable/offline.png
--------------------------------------------------------------------------------
/base/src/main/res/drawable/online.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/base/src/main/res/drawable/online.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':cli', ':http'
2 |
3 | if (!settings.hasProperty("skipAndroidBuild")) {
4 | include ':base', ':app'
5 | }
6 |
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/gif.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/gif.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/home.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/home.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/jpg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/jpg.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/pdf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/pdf.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/png.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/png.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/zip.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/zip.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/folder.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/img/default.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/img/default.png
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/piotrpolak/android-http-server/HEAD/app/src/main/assets/public/assets/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/app/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/app/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 |
6 |
--------------------------------------------------------------------------------
/app/src/main/assets/public/assets/css/styles.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 70px;
3 | }
4 | .form-login, .box-logout {
5 | max-width: 330px;
6 | padding: 15px;
7 | margin: 0 auto;
8 | }
9 | .form-login input {
10 | margin-bottom: 10px;
11 | }
12 | .container {
13 | max-width: 700px;
14 | }
15 | .bg-info {
16 | padding: 10px;
17 | }
--------------------------------------------------------------------------------
/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | HTTPServer
4 | HTTP daemon started
5 | HTTP daemon stopped
6 | HTTP daemon
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/menu/menu_main.xml:
--------------------------------------------------------------------------------
1 |
7 |
--------------------------------------------------------------------------------
/base/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/app/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/AccessDeniedException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception;
9 |
10 | /**
11 | * Access denied exception.
12 | */
13 | public class AccessDeniedException extends RuntimeException {
14 | }
15 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/MethodNotAllowedException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception;
9 |
10 | /**
11 | * Method not allowed exception.
12 | */
13 | public class MethodNotAllowedException extends RuntimeException {
14 | }
15 |
--------------------------------------------------------------------------------
/app/src/main/assets/conf/httpd.properties:
--------------------------------------------------------------------------------
1 | # server.port=8080
2 | server.static.path=./www/
3 | server.static.directoryIndex=index.html,index.htm,Index
4 | server.mimeType.filePath=mime.type
5 | server.mimeType.defaultMimeType=text/plain
6 | server.maxThreads=10
7 | server.keepAlive.enabled=false
8 |
9 | #server.errorDocument.404=./errors/404.html
10 | #server.errorDocument.403=./errors/403.html
11 |
12 | admin.login=admin
13 | admin.password=1234
14 | admin.driveAccess.enabled=true
15 |
16 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/OsUtils.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http;
2 |
3 | import java.util.Locale;
4 |
5 | // CHECKSTYLE.OFF: JavadocType
6 | public final class OsUtils {
7 |
8 | private OsUtils() {
9 | }
10 |
11 | /**
12 | * Tells whether the current runtime is Windows OS.
13 | *
14 | * @return
15 | */
16 | public static boolean isWindows() {
17 | return System.getProperty("os.name", "unknown").toLowerCase(Locale.ROOT).contains("win");
18 | }
19 | }
20 | // CHECKSTYLE.ON: JavadocType
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #built application files
2 | *.apk
3 | *.ap_
4 |
5 | # files for the dex VM
6 | *.dex
7 |
8 | # Java class files
9 | *.class
10 |
11 | # generated files
12 | bin/
13 | gen/
14 |
15 | # Local configuration file (sdk path, etc)
16 | local.properties
17 |
18 | # Windows thumbnail db
19 | Thumbs.db
20 |
21 | # OSX files
22 | .DS_Store
23 |
24 | # Eclipse project files
25 | .classpath
26 | .project
27 |
28 | # Android Studio
29 | *.iml
30 | .idea
31 | *.iml
32 | #.idea/workspace.xml - remove # and delete .idea if it better suit your needs.
33 | .gradle
34 | build/
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/protocol/parser/MalformedInputException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2016-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.protocol.parser;
9 |
10 | /**
11 | * Malformed input exception.
12 | */
13 | public class MalformedInputException extends Exception {
14 |
15 | public MalformedInputException(final String s) {
16 | super(s);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/ServletOutputStream.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | import java.io.OutputStream;
11 |
12 | /**
13 | * Servlet output stream.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 201610
17 | */
18 | public abstract class ServletOutputStream extends OutputStream {
19 | }
20 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/FilterInitializationException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception;
9 |
10 | /**
11 | * Filter initialization exception.
12 | */
13 | public class FilterInitializationException extends Exception {
14 |
15 | public FilterInitializationException(final Throwable throwable) {
16 | super(throwable);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/ServletInitializationException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception;
9 |
10 | /**
11 | * Servlet initialization exception.
12 | */
13 | public class ServletInitializationException extends Exception {
14 |
15 | public ServletInitializationException(final Throwable throwable) {
16 | super(throwable);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/UnsupportedProtocolException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Unsupported protocol.
12 | */
13 | public class UnsupportedProtocolException extends ProtocolException {
14 |
15 | public UnsupportedProtocolException(final String message) {
16 | super(message);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/UriTooLongProtocolException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * URI exceeds URI limit.
12 | */
13 | public class UriTooLongProtocolException extends ProtocolException {
14 |
15 | public UriTooLongProtocolException(final String message) {
16 | super(message);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/NotFoundException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception;
9 |
10 | /**
11 | * Not found exception.
12 | */
13 | public class NotFoundException extends RuntimeException {
14 |
15 | public NotFoundException() {
16 | }
17 |
18 | public NotFoundException(final String message) {
19 | super(message);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/LengthRequiredException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Length required exception.
12 | */
13 | public class LengthRequiredException extends ProtocolException {
14 | public LengthRequiredException() {
15 | super("Length header is required for POST requests.");
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/PayloadTooLargeProtocolException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Payload too large.
12 | */
13 | public class PayloadTooLargeProtocolException extends ProtocolException {
14 |
15 | public PayloadTooLargeProtocolException(final String message) {
16 | super(message);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/MalformedStatusLineException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Malformed status line exception.
12 | */
13 | public class MalformedStatusLineException extends ProtocolException {
14 |
15 | public MalformedStatusLineException(final String message) {
16 | super(message);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/HttpErrorHandlerResolver.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler;
9 |
10 | /**
11 | * Resolves HttpErrorHandler for given runtime exception.
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @since 201708
15 | */
16 | public interface HttpErrorHandlerResolver {
17 | HttpErrorHandler getHandler(RuntimeException e);
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/StatusLineTooLongProtocolException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Status line exceeds its limit.
12 | */
13 | public class StatusLineTooLongProtocolException extends ProtocolException {
14 |
15 | public StatusLineTooLongProtocolException(final String message) {
16 | super(message);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/ServletConfig.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2016-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | /**
11 | * Servlet config.
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @since 201610
15 | */
16 | public interface ServletConfig {
17 |
18 | /**
19 | * Returns servlet context.
20 | *
21 | * @return
22 | */
23 | ServletContext getServletContext();
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/FilterConfig.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | /**
11 | * Filter config.
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @since 201803
15 | */
16 | public interface FilterConfig {
17 |
18 | /**
19 | * Returns associated servlet context.
20 | *
21 | * @return
22 | */
23 | ServletContext getServletContext();
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/RangeNotSatisfiableProtocolException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Exception thrown when range is not satisfiable and can not be served.
12 | */
13 | public class RangeNotSatisfiableProtocolException extends ProtocolException {
14 |
15 | public RangeNotSatisfiableProtocolException() {
16 | super("Range not satisfiable");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/configuration/ServerConfigFactory.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.configuration;
9 |
10 | /**
11 | * Server config factory.
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @since 201611
15 | */
16 | public interface ServerConfigFactory {
17 |
18 | /**
19 | * Produces and returns server config.
20 | *
21 | * @return
22 | */
23 | ServerConfig getServerConfig();
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/MalformedOrUnsupportedMethodProtocolException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Method too long or unknown (not supported).
12 | */
13 | public class MalformedOrUnsupportedMethodProtocolException extends ProtocolException {
14 |
15 | public MalformedOrUnsupportedMethodProtocolException(final String message) {
16 | super(message);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/gui/ServerGui.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2015
6 | **************************************************/
7 |
8 | package ro.polak.http.gui;
9 |
10 | /**
11 | * Defines methods that should be implemented by the server runner GUI (CLI, Swing, Android..).
12 | */
13 | public interface ServerGui {
14 |
15 | /**
16 | * GUI method called by controller on stop.
17 | */
18 | void stop();
19 |
20 | /**
21 | * GUI method called by controller on start.
22 | */
23 | void start();
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/utilities/DateProviderTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.utilities;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.util.Date;
6 |
7 | import static org.hamcrest.MatcherAssert.assertThat;
8 | import static org.hamcrest.Matchers.is;
9 | import static org.hamcrest.Matchers.lessThanOrEqualTo;
10 |
11 | // CHECKSTYLE.OFF: JavadocType
12 | public class DateProviderTest {
13 |
14 | @Test
15 | public void shouldReturnAValidDate() throws Exception {
16 | DateProvider dateProvider = new DateProvider();
17 | assertThat(dateProvider.now().getTime(), is(lessThanOrEqualTo(new Date().getTime())));
18 | }
19 | }
20 | // CHECKSTYLE.ON: JavadocType
21 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/protocol/ProtocolException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.exception.protocol;
9 |
10 | /**
11 | * Generic protocol exception.
12 | */
13 | public class ProtocolException extends RuntimeException {
14 |
15 | public ProtocolException(final String message) {
16 | super(message);
17 | }
18 |
19 | public ProtocolException(final String s, final Throwable throwable) {
20 | super(s, throwable);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/utilities/DateProvider.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2017-2017
6 | **************************************************/
7 | package ro.polak.http.utilities;
8 |
9 | import java.util.Date;
10 |
11 | /**
12 | * Date provider. Makes testing deterministic.
13 | *
14 | * @author Piotr Polak piotr [at] polak [dot] ro
15 | * @since 201710
16 | */
17 | public class DateProvider {
18 |
19 | /**
20 | * Returns the current date.
21 | *
22 | * @return
23 | */
24 | public Date now() {
25 | return new Date();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/MimeTypeMapping.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http;
9 |
10 | /**
11 | * Mime type mapping.
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @since 200802
15 | */
16 | public interface MimeTypeMapping {
17 |
18 | /**
19 | * Returns mime type for specified extension.
20 | *
21 | * @param extension extension
22 | * @return mime type for specified extension
23 | */
24 | String getMimeTypeByExtension(String extension);
25 | }
26 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/polak/webserver/base/ConfigurationException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.webserver.base;
9 |
10 | /**
11 | * Represents a configuration exception.
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @since 201710
15 | */
16 | public class ConfigurationException extends RuntimeException {
17 |
18 | public ConfigurationException(final String s) {
19 | super(s);
20 | }
21 |
22 | public ConfigurationException(final Throwable e) {
23 | super(e);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/ServletException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception;
9 |
10 | /**
11 | * Default servlet exception.
12 | */
13 | public class ServletException extends Exception {
14 |
15 | public ServletException(final String s) {
16 | super(s);
17 | }
18 |
19 | public ServletException(final String s, final Throwable throwable) {
20 | super(s, throwable);
21 | }
22 |
23 | public ServletException(final Throwable throwable) {
24 | super(throwable);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/installsdk.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | wget https://dl.google.com/android/repository/commandlinetools-linux-6858069_latest.zip -P/tmp && \
4 | unzip /tmp/commandlinetools-linux-6858069_latest.zip -d ~/android-sdk && \
5 | unlink /tmp/commandlinetools-linux-6858069_latest.zip && \
6 | export ANDROID_HOME=~/android-sdk && \
7 | mv $ANDROID_HOME/cmdline-tools/ $ANDROID_HOME/latest && \
8 | mkdir $ANDROID_HOME/cmdline-tools/ && \
9 | mv $ANDROID_HOME/latest $ANDROID_HOME/cmdline-tools/latest && \
10 | mkdir -p ~/.android && \
11 | touch ~/.android/repositories.cfg && \
12 | yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager "platform-tools" "platforms;android-26" && \
13 | yes | $ANDROID_HOME/cmdline-tools/latest/bin/sdkmanager --licenses
14 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/BasicAbstractFilter.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2019-2020
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | /**
11 | * Basic filter, does not require initialization.
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @since 202001
15 | */
16 | public abstract class BasicAbstractFilter implements Filter {
17 |
18 | /**
19 | * Does nothing.
20 | *
21 | * @param filterConfig
22 | */
23 | @Override
24 | public void init(final FilterConfig filterConfig) {
25 | // Do Nothing
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/protocol/serializer/Serializer.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2016-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.protocol.serializer;
9 |
10 | /**
11 | * Generic serializer interface.
12 | *
13 | * @param the type of the input.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 201611
17 | */
18 | public interface Serializer {
19 |
20 | /**
21 | * Produced serialized string representation of the input attribute.
22 | *
23 | * @param input
24 | * @return
25 | */
26 | String serialize(T input);
27 | }
28 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/protocol/parser/Parser.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2016-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.protocol.parser;
9 |
10 | /**
11 | * Generic parser interface.
12 | *
13 | * @param the parse output type.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 201611
17 | */
18 | public interface Parser {
19 |
20 | /**
21 | * Parses input string into the destination format.
22 | *
23 | * @param input
24 | * @return
25 | * @throws MalformedInputException
26 | */
27 | T parse(String input) throws MalformedInputException;
28 | }
29 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/Range.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2017-2017
6 | **************************************************/
7 | package ro.polak.http.servlet;
8 |
9 | /**
10 | * Represents HTTP range.
11 | *
12 | * @author Piotr Polak piotr [at] polak [dot] ro
13 | * @since 201702
14 | */
15 | public final class Range {
16 |
17 | private long from;
18 | private long to;
19 |
20 | public Range(final long from, final long to) {
21 | this.from = from;
22 | this.to = to;
23 | }
24 |
25 | public long getFrom() {
26 | return from;
27 | }
28 |
29 | public long getTo() {
30 | return to;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/resource/provider/ResourceProvider.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2015
6 | **************************************************/
7 |
8 | package ro.polak.http.resource.provider;
9 |
10 | import ro.polak.http.Loadable;
11 |
12 | /**
13 | * Interface used for loading certain types of HTTP resources.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 201610
17 | */
18 | public interface ResourceProvider extends Loadable {
19 |
20 | /**
21 | * Tells whether this resource provider can load resource for given path.
22 | *
23 | * @param path
24 | * @return
25 | */
26 | boolean canLoad(String path);
27 | }
28 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError400Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractPlainTextHttpErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 400 Bad Request.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError400Handler extends AbstractPlainTextHttpErrorHandler {
20 |
21 | public HttpError400Handler() {
22 | super(HttpServletResponse.STATUS_BAD_REQUEST, "Error 400 - Bad Request");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/HttpErrorHandler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler;
9 |
10 | import java.io.IOException;
11 |
12 | import ro.polak.http.servlet.HttpServletResponse;
13 |
14 | /**
15 | * IHTTPError interface defining serve method.
16 | *
17 | * @author Piotr Polak piotr [at] polak [dot] ro
18 | * @since 201509
19 | */
20 | public interface HttpErrorHandler {
21 |
22 | /**
23 | * Serves the error page.
24 | *
25 | * @param response
26 | * @throws IOException
27 | */
28 | void serve(HttpServletResponse response) throws IOException;
29 | }
30 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError414Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractPlainTextHttpErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 414 URI Too Long.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError414Handler extends AbstractPlainTextHttpErrorHandler {
20 |
21 | public HttpError414Handler() {
22 | super(HttpServletResponse.STATUS_URI_TOO_LONG, "Error 414 - URI Too Long");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/exception/UnexpectedSituationException.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2017-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.exception;
9 |
10 | /**
11 | * Generic unrecoverable runtime exception.
12 | */
13 | public class UnexpectedSituationException extends RuntimeException {
14 |
15 | public UnexpectedSituationException(final String message) {
16 | super(message);
17 | }
18 |
19 | public UnexpectedSituationException(final String message, final Throwable e) {
20 | super(message, e);
21 | }
22 |
23 | public UnexpectedSituationException(final Throwable e) {
24 | super(e);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError411Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractPlainTextHttpErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 411 Length required.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError411Handler extends AbstractPlainTextHttpErrorHandler {
20 |
21 | public HttpError411Handler() {
22 | super(HttpServletResponse.STATUS_LENGTH_REQUIRED, "Error 411 - Length Required");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/servlet/impl/ServletConfigImplTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.servlet.impl;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.hamcrest.MatcherAssert.assertThat;
6 | import static org.hamcrest.Matchers.is;
7 | import static org.hamcrest.Matchers.nullValue;
8 | import static org.hamcrest.core.IsNot.not;
9 | import static org.mockito.Mockito.mock;
10 |
11 | // CHECKSTYLE.OFF: JavadocType
12 | public class ServletConfigImplTest {
13 |
14 | @Test
15 | public void shouldWorkSetterAndGetter() {
16 | ServletContextImpl servletContextImpl = mock(ServletContextImpl.class);
17 | ServletConfigImpl servletConfigImpl = new ServletConfigImpl(servletContextImpl);
18 | assertThat(servletConfigImpl.getServletContext(), is(not(nullValue())));
19 | }
20 | }
21 | // CHECKSTYLE.ON: JavadocType
22 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError413Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractPlainTextHttpErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 413 Request Entity Too Large.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError413Handler extends AbstractPlainTextHttpErrorHandler {
20 |
21 | public HttpError413Handler() {
22 | super(HttpServletResponse.REQUEST_ENTITY_TOO_LARGE, "Error 413 Request Entity Too Large");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError416Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2017-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractPlainTextHttpErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 416 Requested Range Not Satisfiable.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201701
18 | */
19 | public class HttpError416Handler extends AbstractPlainTextHttpErrorHandler {
20 |
21 | public HttpError416Handler() {
22 | super(HttpServletResponse.STATUS_RANGE_NOT_SATISFIABLE, "Error 416 Range Not Satisfiable");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError503Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractPlainTextHttpErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 503 Service Unavailable HTTP error handler.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError503Handler extends AbstractPlainTextHttpErrorHandler {
20 |
21 | public HttpError503Handler() {
22 | super(HttpServletResponse.STATUS_SERVICE_UNAVAILABLE, "Error 503 - Service Unavailable");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError505Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractPlainTextHttpErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 505 HTTP Version Not Supported error handler.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError505Handler extends AbstractPlainTextHttpErrorHandler {
20 |
21 | public HttpError505Handler() {
22 | super(HttpServletResponse.HTTP_VERSION_NOT_SUPPORTED, "Error 505 - HTTP Version Not Supported");
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/admin/LogoutServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package admin;
9 |
10 | import ro.polak.http.exception.ServletException;
11 | import ro.polak.http.servlet.HttpServlet;
12 | import ro.polak.http.servlet.HttpServletRequest;
13 | import ro.polak.http.servlet.HttpServletResponse;
14 |
15 | /**
16 | * Logout servlet. The logout procedure is captured in a LogoutFilter.
17 | */
18 | public class LogoutServlet extends HttpServlet {
19 |
20 | /**
21 | * {@inheritDoc}
22 | */
23 | @Override
24 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
25 | // Logout using filter
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/utilities/DateUtilitiesTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.utilities;
2 |
3 | import org.hamcrest.CoreMatchers;
4 | import org.junit.jupiter.api.Test;
5 |
6 | import java.util.Date;
7 |
8 | import static org.hamcrest.MatcherAssert.assertThat;
9 | import static org.hamcrest.core.Is.is;
10 | import static ro.polak.http.ExtraMarchers.utilityClass;
11 |
12 | // CHECKSTYLE.OFF: JavadocType
13 | public class DateUtilitiesTest {
14 |
15 | @Test
16 | public void shouldNotBeInstantiableFinalClass() {
17 | assertThat(DateUtilities.class, CoreMatchers.is(utilityClass()));
18 | }
19 |
20 | // CHECKSTYLE.OFF: MagicNumber
21 | @Test
22 | public void shouldFormatDate() {
23 | assertThat(DateUtilities.dateFormat(new Date(1520881821937L)), is("Mon, 12 Mar 2018 19:10:21 GMT"));
24 | }
25 | // CHECKSTYLE.ON: MagicNumber
26 | }
27 | // CHECKSTYLE.ON: JavadocType
28 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/configuration/ServletMapping.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2018-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.configuration;
9 |
10 | import java.util.regex.Pattern;
11 |
12 | import ro.polak.http.servlet.HttpServlet;
13 |
14 | /**
15 | * Represents Servlet to URL patter mapping.
16 | *
17 | * @author Piotr Polak piotr [at] polak [dot] ro
18 | * @since 201803
19 | */
20 | public interface ServletMapping {
21 |
22 | /**
23 | * Returns registration URL pattern.
24 | *
25 | * @return
26 | */
27 | Pattern getUrlPattern();
28 |
29 | /**
30 | * Returns mapped servlet class.
31 | *
32 | * @return
33 | */
34 | Class extends HttpServlet> getServletClass();
35 | }
36 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError403Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractHtmlErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 403 Forbidden HTTP error handler.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError403Handler extends AbstractHtmlErrorHandler {
20 |
21 | public HttpError403Handler(final String errorDocumentPath) {
22 | super(HttpServletResponse.STATUS_ACCESS_DENIED, "Error 403 - Forbidden", "Access Denied.
",
23 | errorDocumentPath);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/http/src/main/java/example/NotFoundServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package example;
9 |
10 | import ro.polak.http.exception.NotFoundException;
11 | import ro.polak.http.exception.ServletException;
12 | import ro.polak.http.servlet.HttpServlet;
13 | import ro.polak.http.servlet.HttpServletRequest;
14 | import ro.polak.http.servlet.HttpServletResponse;
15 |
16 | /**
17 | * Not found page example page.
18 | */
19 | public class NotFoundServlet extends HttpServlet {
20 |
21 | /**
22 | * {@inheritDoc}
23 | */
24 | @Override
25 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
26 | throw new NotFoundException();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/http/src/main/java/example/ForbiddenServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package example;
9 |
10 | import ro.polak.http.exception.AccessDeniedException;
11 | import ro.polak.http.exception.ServletException;
12 | import ro.polak.http.servlet.HttpServlet;
13 | import ro.polak.http.servlet.HttpServletRequest;
14 | import ro.polak.http.servlet.HttpServletResponse;
15 |
16 | /**
17 | * Forbidden page example.
18 | */
19 | public class ForbiddenServlet extends HttpServlet {
20 |
21 | /**
22 | * {@inheritDoc}
23 | */
24 | @Override
25 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
26 | throw new AccessDeniedException();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/http/src/main/java/example/InternalServerErrorServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package example;
9 |
10 | import ro.polak.http.exception.ServletException;
11 | import ro.polak.http.servlet.HttpServlet;
12 | import ro.polak.http.servlet.HttpServletRequest;
13 | import ro.polak.http.servlet.HttpServletResponse;
14 |
15 | /**
16 | * Internal server error page example page.
17 | */
18 | public class InternalServerErrorServlet extends HttpServlet {
19 |
20 | /**
21 | * {@inheritDoc}
22 | */
23 | @Override
24 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
25 | throw new ServletException("Something bad has just happened");
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/controller/Controller.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2015
6 | **************************************************/
7 |
8 | package ro.polak.http.controller;
9 |
10 | import ro.polak.http.WebServer;
11 |
12 | /**
13 | * Defines methods that must be implemented by the server controller.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 201012
17 | */
18 | public interface Controller {
19 |
20 | /**
21 | * Starts the server logic.
22 | */
23 | void start() throws IllegalStateException;
24 |
25 | /**
26 | * Stops the server logic.
27 | */
28 | void stop() throws IllegalStateException;
29 |
30 | /**
31 | * Returns web server instance.
32 | *
33 | * @return
34 | */
35 | WebServer getWebServer();
36 | }
37 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/FilterChain.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | import java.io.IOException;
11 |
12 | import ro.polak.http.exception.ServletException;
13 |
14 | /**
15 | * Filter chain interface easing running filters.
16 | *
17 | * @author Piotr Polak piotr [at] polak [dot] ro
18 | * @since 201803
19 | */
20 | public interface FilterChain {
21 |
22 | /**
23 | * Filters use the FilterChain to invoke the next filter in the chain.
24 | *
25 | * @param request
26 | * @param response
27 | * @throws IOException
28 | * @throws ServletException
29 | */
30 | void doFilter(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
31 | }
32 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError404Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import ro.polak.http.errorhandler.AbstractHtmlErrorHandler;
11 | import ro.polak.http.servlet.HttpServletResponse;
12 |
13 | /**
14 | * 404 File Not Found HTTP error handler.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201509
18 | */
19 | public class HttpError404Handler extends AbstractHtmlErrorHandler {
20 |
21 | public HttpError404Handler(final String errorDocumentPath) {
22 | super(HttpServletResponse.STATUS_NOT_FOUND, "Error 404 - File Not Found",
23 | "The server has not found anything matching the specified URL.
",
24 | errorDocumentPath);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/controller/impl/LoggingUncaughtExceptionHandlerTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.controller.impl;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.mockito.Mockito.mock;
6 | import static org.mockito.Mockito.times;
7 | import static org.mockito.Mockito.verify;
8 | import static org.mockito.Mockito.when;
9 |
10 | // CHECKSTYLE.OFF: JavadocType
11 | public class LoggingUncaughtExceptionHandlerTest {
12 |
13 | @Test
14 | public void shouldLogException() {
15 | Thread.UncaughtExceptionHandler handler
16 | = new ControllerImpl.LoggingUncaughtExceptionHandler();
17 |
18 | Throwable throwable = mock(Throwable.class);
19 | when(throwable.getStackTrace()).thenReturn(new StackTraceElement[]{new StackTraceElement("X", "X", "X", 1)});
20 | handler.uncaughtException(Thread.currentThread(), throwable);
21 |
22 | verify(throwable, times(1)).getStackTrace();
23 | }
24 | }
25 | // CHECKSTYLE.ON: JavadocType
26 |
--------------------------------------------------------------------------------
/http/src/main/java/example/ForbiddenByFilterServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package example;
9 |
10 | import java.io.PrintWriter;
11 |
12 | import ro.polak.http.exception.ServletException;
13 | import ro.polak.http.servlet.HttpServlet;
14 | import ro.polak.http.servlet.HttpServletRequest;
15 | import ro.polak.http.servlet.HttpServletResponse;
16 |
17 | /**
18 | * Forbidden by filter page example.
19 | */
20 | public class ForbiddenByFilterServlet extends HttpServlet {
21 |
22 | /**
23 | * {@inheritDoc}
24 | */
25 | @Override
26 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
27 | PrintWriter printWriter = response.getWriter();
28 | printWriter.println("Hello World!");
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/base/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.library'
2 |
3 | buildscript {
4 | dependencies {
5 | classpath 'com.android.tools.build:gradle:4.2.0'
6 |
7 | // NOTE: Do not place your application dependencies here; they belong
8 | // in the individual module build.gradle files
9 | }
10 | repositories {
11 | jcenter()
12 | google()
13 | }
14 | }
15 |
16 | android {
17 | compileSdkVersion 29
18 | buildToolsVersion '30.0.2'
19 | defaultConfig {
20 | minSdkVersion 19
21 | targetSdkVersion 29
22 | versionCode 1
23 | versionName "1.0"
24 | }
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | }
29 | }
30 | productFlavors {
31 | }
32 | }
33 |
34 | dependencies {
35 | implementation fileTree(dir: 'libs', include: ['*.jar'])
36 | implementation 'androidx.appcompat:appcompat:1.0.0'
37 | implementation project(path: ':http')
38 | implementation project(path: ':cli')
39 | }
40 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/configuration/FilterMapping.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2018-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.configuration;
9 |
10 | import java.util.regex.Pattern;
11 |
12 | import ro.polak.http.servlet.Filter;
13 |
14 | /**
15 | * Represents Filter to URL patter mapping.
16 | *
17 | * @author Piotr Polak piotr [at] polak [dot] ro
18 | * @since 201803
19 | */
20 | public interface FilterMapping {
21 |
22 | /**
23 | * Returns registration URL pattern.
24 | *
25 | * @return
26 | */
27 | Pattern getUrlPattern();
28 |
29 | /**
30 | * Returns registration excluded URL pattern.
31 | *
32 | * @return
33 | */
34 | Pattern getUrlExcludePattern();
35 |
36 | /**
37 | * Returns mapped servlet class.
38 | *
39 | * @return
40 | */
41 | Class extends Filter> getFilterClass();
42 | }
43 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/servlet/loader/SampleFilter.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.servlet.loader;
2 |
3 | import ro.polak.http.servlet.Filter;
4 | import ro.polak.http.servlet.FilterChain;
5 | import ro.polak.http.servlet.FilterConfig;
6 | import ro.polak.http.servlet.HttpServletRequest;
7 | import ro.polak.http.servlet.HttpServletResponse;
8 |
9 | // CHECKSTYLE.OFF: DesignForExtension JavadocType
10 | // CHECKSTYLE.OFF: JavadocType
11 | public class SampleFilter implements Filter {
12 |
13 | private FilterConfig filterConfig;
14 |
15 | @Override
16 | public void init(final FilterConfig filterConfig) {
17 | this.filterConfig = filterConfig;
18 | }
19 |
20 | @Override
21 | public void doFilter(final HttpServletRequest request, final HttpServletResponse response,
22 | final FilterChain filterChain) {
23 | // Do Nothing
24 | }
25 |
26 | public FilterConfig getFilterConfig() {
27 | return filterConfig;
28 | }
29 | }
30 | // CHECKSTYLE.ON: JavadocType
31 | // CHECKSTYLE.ON: DesignForExtension
32 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/servlet/ServletPrintWriterTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.servlet;
2 |
3 | import org.junit.jupiter.api.Test;
4 | import org.junit.jupiter.api.function.Executable;
5 |
6 | import static org.junit.jupiter.api.Assertions.assertThrows;
7 | import static org.junit.jupiter.api.Assertions.fail;
8 | import static org.mockito.Mockito.mock;
9 |
10 | // CHECKSTYLE.OFF: JavadocType
11 | public class ServletPrintWriterTest {
12 |
13 | @Test
14 | public void shouldNotAllowToWriteEndMoreThanOnce() {
15 | final ServletPrintWriter servletPrintWriter = new ServletPrintWriter(mock(ServletOutputStream.class));
16 | try {
17 | servletPrintWriter.writeEnd();
18 | } catch (Throwable e) {
19 | fail("Should not throw any exception here");
20 | }
21 |
22 | assertThrows(IllegalStateException.class, new Executable() {
23 | @Override
24 | public void execute() {
25 | servletPrintWriter.writeEnd();
26 | }
27 | });
28 | }
29 | }
30 | // CHECKSTYLE.ON: JavadocType
31 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/impl/FilterConfigImpl.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet.impl;
9 |
10 | import ro.polak.http.servlet.FilterConfig;
11 | import ro.polak.http.servlet.ServletContext;
12 |
13 | /**
14 | * Default config.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201803
18 | */
19 | public class FilterConfigImpl implements FilterConfig {
20 |
21 | private final ServletContext servletContext;
22 |
23 | /**
24 | * Default constructor.
25 | *
26 | * @param servletContext
27 | */
28 | public FilterConfigImpl(final ServletContext servletContext) {
29 | this.servletContext = servletContext;
30 | }
31 |
32 | /**
33 | * {@inheritDoc}
34 | */
35 | @Override
36 | public ServletContext getServletContext() {
37 | return servletContext;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Based on https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes
2 | # See https://help.github.com/articles/dealing-with-line-endings/
3 |
4 | * text=auto
5 |
6 | # Convert crlf => lf for the specified files
7 |
8 | # source code
9 | *.java text eol=lf
10 | *.css text eol=lf
11 | *.sass text eol=lf
12 | *.scss text eol=lf
13 | *.js text eol=lf
14 | *.json text eol=lf
15 | *.htm text eol=lf
16 | *.html text eol=lf
17 | *.xml text eol=lf
18 | *.iml text eol=lf
19 | *.svg text eol=lf
20 | *.txt text eol=lf
21 | *.ini text eol=lf
22 | *.inc text eol=lf
23 | *.pl text eol=lf
24 | *.rb text eol=lf
25 | *.scm text eol=lf
26 | *.sql text eol=lf
27 | *.sh text eol=lf
28 |
29 | # git config
30 | .gitattributes text eol=lf
31 | .gitignore text eol=lf
32 | .gitconfig text eol=lf
33 |
34 | # misc config
35 | *.yaml text eol=lf
36 | *.yml text eol=lf
37 | *.gradle text eol=lf
38 | *.properties text eol=lf
39 |
40 | # Documentation
41 | *.md text eol=lf
42 | LICENSE text eol=lf
43 | AUTHORS text eol=lf
44 |
45 | # (binary is a macro for -text -diff), leave them unouched
46 | *.png binary
47 | *.jpg binary
48 | *.jar
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | buildscript {
4 | dependencies {
5 | classpath 'com.android.tools.build:gradle:4.2.0'
6 |
7 | // NOTE: Do not place your application dependencies here; they belong
8 | // in the individual module build.gradle files
9 | }
10 | repositories {
11 | jcenter()
12 | google()
13 | }
14 | }
15 |
16 | android {
17 | compileSdkVersion 29
18 | buildToolsVersion '30.0.2'
19 | defaultConfig {
20 | applicationId "ro.polak.webserver"
21 | minSdkVersion 19
22 | targetSdkVersion 29
23 | versionCode 1
24 | versionName "1.0"
25 | }
26 | buildTypes {
27 | release {
28 | minifyEnabled false
29 | }
30 | }
31 | productFlavors {
32 | }
33 | }
34 |
35 | dependencies {
36 | implementation fileTree(dir: 'libs', include: ['*.jar'])
37 | implementation 'androidx.appcompat:appcompat:1.0.0'
38 | implementation project(path: ':http')
39 | implementation project(path: ':cli')
40 | implementation project(path: ':base')
41 | }
42 |
--------------------------------------------------------------------------------
/cli/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'java'
2 | apply plugin: 'eclipse'
3 |
4 | compileJava {
5 | sourceCompatibility = 1.7
6 | }
7 |
8 | compileTestJava {
9 | sourceCompatibility = 1.8
10 | }
11 |
12 | jar {
13 | manifest {
14 | attributes 'Main-Class': 'ro.polak.http.cli.DefaultCliServerGui'
15 | }
16 | }
17 |
18 | task fatJar(type: Jar) {
19 | manifest {
20 | attributes 'Implementation-Title': 'StandaloneHTTP server',
21 | 'Main-Class': 'ro.polak.http.cli.DefaultCliServerGui'
22 | }
23 | baseName = project.name + '-all'
24 | from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
25 | with jar
26 | }
27 |
28 | dependencies {
29 | implementation fileTree(dir: 'libs', include: ['*.jar'])
30 | implementation project(path: ':http')
31 | }
32 |
33 |
34 | task(bootRun, dependsOn: fatJar) {
35 | doLast {
36 | print "$buildDir/libs/cli.jar"
37 | javaexec {
38 | main = "-jar"
39 | args = [
40 | "$buildDir/libs/cli-all.jar"
41 | ]
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/impl/ServletConfigImpl.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2016-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet.impl;
9 |
10 | import ro.polak.http.servlet.ServletConfig;
11 | import ro.polak.http.servlet.ServletContext;
12 |
13 | /**
14 | * Servlet config implementation.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201610
18 | */
19 | public class ServletConfigImpl implements ServletConfig {
20 |
21 | private final ServletContext servletContext;
22 |
23 | /**
24 | * Default constructor.
25 | *
26 | * @param servletContext
27 | */
28 | public ServletConfigImpl(final ServletContext servletContext) {
29 | this.servletContext = servletContext;
30 | }
31 |
32 | /**
33 | * {@inheritDoc}
34 | */
35 | @Override
36 | public ServletContext getServletContext() {
37 | return servletContext;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/errorhandler/impl/HttpErrorHandlerResolverImplTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.errorhandler.impl;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import ro.polak.http.configuration.ServerConfig;
6 | import ro.polak.http.errorhandler.HttpErrorHandler;
7 | import ro.polak.http.errorhandler.HttpErrorHandlerResolver;
8 | import ro.polak.http.exception.NotFoundException;
9 |
10 | import static org.hamcrest.MatcherAssert.assertThat;
11 | import static org.hamcrest.Matchers.instanceOf;
12 | import static org.hamcrest.Matchers.is;
13 |
14 | // CHECKSTYLE.OFF: JavadocType
15 | public class HttpErrorHandlerResolverImplTest {
16 |
17 | @Test
18 | public void shouldCaptureIntermediateExceptions() {
19 | ServerConfig serverConfig = null; // WIll throw NPE
20 | HttpErrorHandlerResolver httpErrorHandlerResolver = new HttpErrorHandlerResolverImpl(serverConfig);
21 | HttpErrorHandler handler = httpErrorHandlerResolver.getHandler(new NotFoundException());
22 | assertThat(handler, is(instanceOf(HttpError500Handler.class)));
23 | }
24 | }
25 | // CHECKSTYLE.ON: JavadocType
26 |
--------------------------------------------------------------------------------
/http/src/main/java/example/filter/FakeSecuredAbstractFilter.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 |
8 | package example.filter;
9 |
10 | import ro.polak.http.exception.AccessDeniedException;
11 | import ro.polak.http.servlet.BasicAbstractFilter;
12 | import ro.polak.http.servlet.FilterChain;
13 | import ro.polak.http.servlet.HttpServletRequest;
14 | import ro.polak.http.servlet.HttpServletResponse;
15 |
16 | /**
17 | * Always throws AccessDeniedException.
18 | *
19 | * @author Piotr Polak piotr [at] polak [dot] ro
20 | * @since 201803
21 | */
22 | public class FakeSecuredAbstractFilter extends BasicAbstractFilter {
23 |
24 | /**
25 | * {@inheritDoc}
26 | */
27 | @Override
28 | public void doFilter(final HttpServletRequest request,
29 | final HttpServletResponse response,
30 | final FilterChain filterChain) {
31 | throw new AccessDeniedException();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/exception/ServletExceptionTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.exception;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.hamcrest.MatcherAssert.assertThat;
6 | import static org.hamcrest.core.Is.is;
7 |
8 | // CHECKSTYLE.OFF: JavadocType
9 | public class ServletExceptionTest {
10 |
11 | @Test
12 | public void shouldOfferStringConstructor() {
13 | Exception exception = new ServletException("SomeMessage");
14 | assertThat(exception.getMessage(), is("SomeMessage"));
15 | }
16 |
17 | @Test
18 | public void shouldOfferStringThrowableConstructor() {
19 | Throwable e = new Exception();
20 | Exception exception = new ServletException("SomeMessage", e);
21 | assertThat(exception.getMessage(), is("SomeMessage"));
22 | assertThat(exception.getCause(), is(e));
23 | }
24 |
25 | @Test
26 | public void shouldThrowableConstructor() {
27 | Throwable e = new Exception();
28 | Exception exception = new ServletException(e);
29 | assertThat(exception.getCause(), is(e));
30 | }
31 | }
32 | // CHECKSTYLE.ON: JavadocType
33 |
--------------------------------------------------------------------------------
/app/src/main/java/ro/polak/webserver/MainService.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.webserver;
9 |
10 | import android.content.Context;
11 | import androidx.annotation.NonNull;
12 |
13 | import impl.AndroidServerConfigFactory;
14 | import ro.polak.webserver.base.BaseMainService;
15 | import ro.polak.webserver.base.impl.BaseAndroidServerConfigFactory;
16 |
17 | /**
18 | * Main application service that holds http server.
19 | *
20 | * @author Piotr Polak piotr [at] polak [dot] ro
21 | * @since 201709
22 | */
23 | public final class MainService extends BaseMainService {
24 |
25 | @NonNull
26 | @Override
27 | protected Class getActivityClass() {
28 | return MainActivity.class;
29 | }
30 |
31 | @NonNull
32 | @Override
33 | protected BaseAndroidServerConfigFactory getServerConfigFactory(final Context context) {
34 | return new AndroidServerConfigFactory(context);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/polak/webserver/base/impl/AndroidCliServerGui.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.webserver.base.impl;
9 |
10 | import ro.polak.http.cli.DefaultCliServerGui;
11 | import ro.polak.http.configuration.ServerConfigFactory;
12 |
13 | /**
14 | * Server CLI interface along with a runner, used to test some of the Android only features.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201611
18 | */
19 | public class AndroidCliServerGui extends DefaultCliServerGui {
20 |
21 | /**
22 | * The main CLI runner method.
23 | *
24 | * @param args
25 | */
26 | public static void main(final String[] args) {
27 | (new AndroidCliServerGui()).init();
28 | }
29 |
30 | /**
31 | * {@inheritDoc}
32 | */
33 | @Override
34 | protected ServerConfigFactory getServerConfigFactory() {
35 | return new BaseAndroidServerConfigFactory(null);
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/ServletPrintWriter.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 | package ro.polak.http.servlet;
8 |
9 | import java.io.OutputStream;
10 | import java.io.PrintWriter;
11 |
12 | /**
13 | * Adds additional writeEnd capability to the default PrintWriter.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 2001709
17 | */
18 | public class ServletPrintWriter extends PrintWriter {
19 |
20 | private boolean wasWriteEndAlreadyCalled = false;
21 |
22 | public ServletPrintWriter(final OutputStream outputStream) {
23 | super(outputStream);
24 | }
25 |
26 | /**
27 | * Writes the end of the message. This method should be called once only.
28 | */
29 | public void writeEnd() {
30 | if (wasWriteEndAlreadyCalled) {
31 | throw new IllegalStateException("This method can be called once only.");
32 | }
33 | wasWriteEndAlreadyCalled = true;
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/Filter.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | import java.io.IOException;
11 |
12 | import ro.polak.http.exception.ServletException;
13 |
14 | /**
15 | * Filter interface.
16 | *
17 | * @author Piotr Polak piotr [at] polak [dot] ro
18 | * @since 201803
19 | */
20 | public interface Filter {
21 |
22 | /**
23 | * Initializes filter.
24 | *
25 | * @param filterConfig
26 | * @throws ServletException
27 | */
28 | void init(FilterConfig filterConfig) throws ServletException;
29 |
30 | /**
31 | * Performs request/response filtering.
32 | *
33 | * @param request
34 | * @param response
35 | * @param filterChain
36 | * @throws IOException
37 | * @throws ServletException
38 | */
39 | void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
40 | throws IOException, ServletException;
41 |
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/exception/UnexpectedSituationExceptionTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.exception;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.hamcrest.MatcherAssert.assertThat;
6 | import static org.hamcrest.core.Is.is;
7 |
8 | // CHECKSTYLE.OFF: JavadocType
9 | public class UnexpectedSituationExceptionTest {
10 |
11 | @Test
12 | public void shouldOfferStringConstructor() {
13 | Exception exception = new UnexpectedSituationException("SomeMessage");
14 | assertThat(exception.getMessage(), is("SomeMessage"));
15 | }
16 |
17 | @Test
18 | public void shouldOfferStringThrowableConstructor() {
19 | Throwable e = new Exception();
20 | Exception exception = new UnexpectedSituationException("SomeMessage", e);
21 | assertThat(exception.getMessage(), is("SomeMessage"));
22 | assertThat(exception.getCause(), is(e));
23 | }
24 |
25 | @Test
26 | public void shouldThrowableConstructor() {
27 | Throwable e = new Exception();
28 | Exception exception = new UnexpectedSituationException(e);
29 | assertThat(exception.getCause(), is(e));
30 | }
31 | }
32 | // CHECKSTYLE.ON: JavadocType
33 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/Loadable.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2015
6 | **************************************************/
7 |
8 | package ro.polak.http;
9 |
10 | import java.io.IOException;
11 |
12 | import ro.polak.http.servlet.impl.HttpServletRequestImpl;
13 | import ro.polak.http.servlet.impl.HttpServletResponseImpl;
14 |
15 | /**
16 | * Interface allowing to load payload into the response.
17 | *
18 | * @author Piotr Polak piotr [at] polak [dot] ro
19 | * @since 201912
20 | */
21 | public interface Loadable {
22 |
23 | /**
24 | * Loads the resource for the given path by copying the stream to the response.getOutputStream().
25 | *
26 | * @param path
27 | * @param request
28 | * @param response
29 | * @return
30 | * @throws IOException
31 | */
32 | void load(String path, HttpServletRequestImpl request, HttpServletResponseImpl response) throws IOException;
33 |
34 | /**
35 | * Shuts down the resource provider if necessary, usually closes all open resources.
36 | */
37 | void shutdown();
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/java/api/logic/MessageDTOMapper.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 | package api.logic;
8 |
9 | import androidx.annotation.NonNull;
10 |
11 | import org.json.JSONException;
12 | import org.json.JSONObject;
13 |
14 | import admin.logic.SmsBox;
15 |
16 | /**
17 | * Maps messages to JSONObjects.
18 | */
19 | public class MessageDTOMapper {
20 |
21 | /**
22 | * Maps message to a JSON object.
23 | *
24 | * @param message
25 | * @return
26 | * @throws JSONException
27 | */
28 | @NonNull
29 | public JSONObject toMessageDTO(final SmsBox.Message message) throws JSONException {
30 | JSONObject messageDTO = new JSONObject();
31 | messageDTO.put("id", message.getId());
32 | messageDTO.put("address", message.getAddress());
33 | messageDTO.put("body", message.getBody());
34 | messageDTO.put("date", message.getDate());
35 | messageDTO.put("date_sent", message.getDateSent());
36 | messageDTO.put("is_incoming", message.isIncoming());
37 | return messageDTO;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/.github/workflows/on_pr.yaml:
--------------------------------------------------------------------------------
1 | name: Build PR
2 |
3 | on:
4 | workflow_dispatch:
5 | pull_request:
6 | branches:
7 | - master
8 |
9 | concurrency:
10 | group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
11 | cancel-in-progress: true
12 |
13 | jobs:
14 | build:
15 | runs-on: ubuntu-latest
16 |
17 | steps:
18 | - uses: actions/checkout@v3
19 | with:
20 | fetch-depth: 0
21 |
22 | - name: Set up JDK 11
23 | uses: actions/setup-java@v2
24 | with:
25 | java-version: '11'
26 | distribution: 'adopt'
27 | cache: gradle
28 |
29 | - name: Validate Gradle wrapper
30 | uses: gradle/wrapper-validation-action@e6e38bacfdf1a337459f332974bb2327a31aaf4b
31 |
32 | - name: Build with Gradle
33 | run: ./gradlew clean build assemble :cli:fatJar --stacktrace
34 |
35 | - name: Cleanup Gradle Cache
36 | # Remove some files from the Gradle cache, so they aren't cached by GitHub Actions.
37 | # Restoring these files from a GitHub Actions cache might cause problems for future builds.
38 | run: |
39 | rm -f ~/.gradle/caches/modules-2/modules-2.lock
40 | rm -f ~/.gradle/caches/modules-2/gc.properties
41 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/PathHelper.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http;
2 |
3 | /**
4 | * Contains methods used for path validation and manipulation.
5 | *
6 | * @author Piotr Polak piotr [at] polak [dot] ro
7 | * @since 201711
8 | */
9 | public class PathHelper {
10 |
11 | private static final String SLASH = "/";
12 |
13 | /**
14 | * Tells whether the given path contains illegal expressions.
15 | *
16 | * @param path
17 | * @return
18 | */
19 | public boolean isPathContainingIllegalCharacters(final String path) {
20 | return path == null || path.startsWith("../") || path.indexOf("/../") != -1;
21 | }
22 |
23 | /**
24 | * Makes sure the last character is a slash.
25 | *
26 | * @param path
27 | * @return
28 | */
29 | public String getNormalizedDirectoryPath(final String path) {
30 | if (isDirectoryPath(path)) {
31 | return path;
32 | }
33 | return path + SLASH;
34 | }
35 |
36 | /**
37 | * Tells whether the path ends with a slash.
38 | *
39 | * @param originalPath
40 | * @return
41 | */
42 | public boolean isDirectoryPath(final String originalPath) {
43 | return originalPath.substring(originalPath.length() - 1).equals(SLASH);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/http/src/main/java/example/ChunkedServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package example;
9 |
10 | import java.io.PrintWriter;
11 |
12 | import ro.polak.http.exception.ServletException;
13 | import ro.polak.http.servlet.HttpServlet;
14 | import ro.polak.http.servlet.HttpServletRequest;
15 | import ro.polak.http.servlet.HttpServletResponse;
16 |
17 | import static ro.polak.http.Headers.HEADER_TRANSFER_ENCODING;
18 |
19 | /**
20 | * Chunked transfer example.
21 | */
22 | public class ChunkedServlet extends HttpServlet {
23 |
24 | /**
25 | * {@inheritDoc}
26 | */
27 | @Override
28 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
29 | response.getHeaders().setHeader(HEADER_TRANSFER_ENCODING, "chunked");
30 | PrintWriter printWriter = response.getWriter();
31 | printWriter.print("This is an example of chunked transfer type. ");
32 | printWriter.flush();
33 | printWriter.print("Chunked transfer type can be used when the final length of the data is not known.");
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/http/src/main/java/example/StreamingServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package example;
9 |
10 | import java.io.IOException;
11 | import java.nio.charset.StandardCharsets;
12 |
13 | import ro.polak.http.exception.ServletException;
14 | import ro.polak.http.servlet.HttpServlet;
15 | import ro.polak.http.servlet.HttpServletRequest;
16 | import ro.polak.http.servlet.HttpServletResponse;
17 |
18 | /**
19 | * Writing to output stream.
20 | */
21 | public class StreamingServlet extends HttpServlet {
22 |
23 | /**
24 | * {@inheritDoc}
25 | */
26 | @Override
27 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
28 | try {
29 | byte[] message = "Writing to output stream directly, without chunking.
".getBytes(StandardCharsets.UTF_8);
30 | response.setContentLength(message.length);
31 | response.getOutputStream().write(message);
32 | } catch (IOException e) {
33 | throw new ServletException("Unable to write to output stream", e);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/impl/FilterChainImpl.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet.impl;
9 |
10 | import java.io.IOException;
11 | import java.util.Deque;
12 |
13 | import ro.polak.http.exception.ServletException;
14 | import ro.polak.http.servlet.Filter;
15 | import ro.polak.http.servlet.FilterChain;
16 | import ro.polak.http.servlet.HttpServletRequest;
17 | import ro.polak.http.servlet.HttpServletResponse;
18 |
19 | /**
20 | * Default FilterChain implementation.
21 | *
22 | * @author Piotr Polak piotr [at] polak [dot] ro
23 | * @since 201803
24 | */
25 | public class FilterChainImpl implements FilterChain {
26 |
27 | private Deque filters;
28 |
29 | public FilterChainImpl(final Deque filters) {
30 | this.filters = filters;
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | @Override
37 | public void doFilter(final HttpServletRequest request, final HttpServletResponse response)
38 | throws IOException, ServletException {
39 |
40 | filters.pop().doFilter(request, response, this);
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/utilities/DateUtilities.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2015
6 | **************************************************/
7 |
8 | package ro.polak.http.utilities;
9 |
10 | import java.text.SimpleDateFormat;
11 | import java.util.Date;
12 | import java.util.Locale;
13 |
14 | import static java.util.TimeZone.getTimeZone;
15 |
16 | /**
17 | * Thread safe date utilities.
18 | *
19 | * @author Piotr Polak piotr [at] polak [dot] ro
20 | * @since 200804
21 | */
22 | public final class DateUtilities {
23 |
24 | private static final String DATE_FORMAT = "EEE, d MMM yyyy HH:mm:ss z";
25 |
26 | private DateUtilities() {
27 | }
28 |
29 | /**
30 | * Formats date into the RFC 822 GMT format. Thread safe.
31 | *
32 | * @param date
33 | * @return
34 | */
35 | public static String dateFormat(final Date date) {
36 | return getNewDateFormat().format(date);
37 | }
38 |
39 | private static SimpleDateFormat getNewDateFormat() {
40 | SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_FORMAT, Locale.US);
41 | simpleDateFormat.setTimeZone(getTimeZone("GMT"));
42 |
43 | return simpleDateFormat;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/PathHelperTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.hamcrest.MatcherAssert.assertThat;
6 | import static org.hamcrest.core.Is.is;
7 |
8 | // CHECKSTYLE.OFF: JavadocType
9 | public class PathHelperTest {
10 |
11 | private static PathHelper pathHelper = new PathHelper();
12 |
13 | @Test
14 | public void shouldNotAcceptInvalidCharacters() {
15 | assertThat(pathHelper.isPathContainingIllegalCharacters("somepath../"), is(false));
16 | assertThat(pathHelper.isPathContainingIllegalCharacters("../somepath"), is(true));
17 | assertThat(pathHelper.isPathContainingIllegalCharacters("somepath/../"), is(true));
18 | assertThat(pathHelper.isPathContainingIllegalCharacters(null), is(true));
19 | }
20 |
21 | @Test
22 | public void shouldNormalizeDirectoryPath() {
23 | assertThat(pathHelper.getNormalizedDirectoryPath("somepath"), is("somepath/"));
24 | assertThat(pathHelper.getNormalizedDirectoryPath("somepath/"), is("somepath/"));
25 | }
26 |
27 | @Test
28 | public void shouldSayWhetherDirectoryPath() {
29 | assertThat(pathHelper.isDirectoryPath("somepath"), is(false));
30 | assertThat(pathHelper.isDirectoryPath("somepath/"), is(true));
31 | }
32 | }
33 | // CHECKSTYLE.ON: JavadocType
34 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/session/storage/SessionStorage.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2016-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.session.storage;
9 |
10 | import java.io.IOException;
11 |
12 | import ro.polak.http.servlet.impl.HttpSessionImpl;
13 |
14 | /**
15 | * Specifies methods required for storing session.
16 | *
17 | * @author Piotr Polak piotr [at] polak [dot] ro
18 | * @since 201610
19 | */
20 | public interface SessionStorage {
21 |
22 | /**
23 | * Persists session, throws exception in case of failure.
24 | *
25 | * @param session
26 | * @throws IOException
27 | */
28 | void persistSession(HttpSessionImpl session) throws IOException;
29 |
30 | /**
31 | * Reads session for the given id. Returns null if there is no such session and throws
32 | * exception in case of failure.
33 | *
34 | * @param id
35 | * @return
36 | * @throws IOException
37 | */
38 | HttpSessionImpl getSession(String id) throws IOException;
39 |
40 | /**
41 | * Removes session.
42 | *
43 | * @param session
44 | * @return
45 | */
46 | boolean removeSession(HttpSessionImpl session);
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/configuration/impl/ServletMappingImpl.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2018-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.configuration.impl;
9 |
10 | import java.util.regex.Pattern;
11 |
12 | import ro.polak.http.configuration.ServletMapping;
13 | import ro.polak.http.servlet.HttpServlet;
14 |
15 | /**
16 | * Default implementation for ServletMapping.
17 | *
18 | * @author Piotr Polak piotr [at] polak [dot] ro
19 | * @since 201803
20 | */
21 | public class ServletMappingImpl implements ServletMapping {
22 |
23 | private final Pattern urlPattern;
24 |
25 | private final Class extends HttpServlet> servletClass;
26 |
27 | public ServletMappingImpl(final Pattern urlPattern, final Class extends HttpServlet> servletClass) {
28 | this.urlPattern = urlPattern;
29 | this.servletClass = servletClass;
30 | }
31 |
32 | /**
33 | * {@inheritDoc}
34 | */
35 | @Override
36 | public Pattern getUrlPattern() {
37 | return urlPattern;
38 | }
39 |
40 | /**
41 | * {@inheritDoc}
42 | */
43 | @Override
44 | public Class extends HttpServlet> getServletClass() {
45 | return servletClass;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/utilities/StringUtilitiesTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.utilities;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.hamcrest.CoreMatchers.is;
6 | import static org.hamcrest.CoreMatchers.not;
7 | import static org.hamcrest.MatcherAssert.assertThat;
8 | import static ro.polak.http.ExtraMarchers.utilityClass;
9 |
10 | // CHECKSTYLE.OFF: JavadocType
11 | public class StringUtilitiesTest {
12 |
13 | @Test
14 | public void shouldNotBeInstantiableFinalClass() {
15 | assertThat(StringUtilities.class, is(utilityClass()));
16 | }
17 |
18 | @Test
19 | public void shouldGenerateTwoDifferentRandomStrings() {
20 | String s1 = StringUtilities.generateRandom();
21 | String s2 = StringUtilities.generateRandom();
22 |
23 | // CHECKSTYLE.OFF: MagicNumber
24 | assertThat(s1.length(), is(32));
25 | assertThat(s2.length(), is(32));
26 | // CHECKSTYLE.ON: MagicNumber
27 | assertThat(s1, is(not(s2)));
28 | }
29 |
30 | @Test
31 | public void shouldDetectEmptyStrings() {
32 | assertThat(StringUtilities.isEmpty(null), is(true));
33 | assertThat(StringUtilities.isEmpty(""), is(true));
34 |
35 | assertThat(StringUtilities.isEmpty(" "), is(false));
36 | assertThat(StringUtilities.isEmpty("a"), is(false));
37 | }
38 | }
39 | // CHECKSTYLE.ON: JavadocType
40 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/RangePartHeader.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2017-2017
6 | **************************************************/
7 | package ro.polak.http;
8 |
9 | import ro.polak.http.servlet.Range;
10 |
11 | /**
12 | * Represents range part header.
13 | *
14 | * @author Piotr Polak piotr [at] polak [dot] ro
15 | * @since 201702
16 | */
17 | public final class RangePartHeader {
18 |
19 | private final Range range;
20 | private final String boundary;
21 | private final String contentType;
22 | private final long totalLength;
23 |
24 | public RangePartHeader(final Range range,
25 | final String boundary,
26 | final String contentType,
27 | final long totalLength) {
28 | this.range = range;
29 | this.boundary = boundary;
30 | this.contentType = contentType;
31 | this.totalLength = totalLength;
32 | }
33 |
34 | public Range getRange() {
35 | return range;
36 | }
37 |
38 | public String getBoundary() {
39 | return boundary;
40 | }
41 |
42 | public String getContentType() {
43 | return contentType;
44 | }
45 |
46 | public long getTotalLength() {
47 | return totalLength;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/protocol/serializer/impl/HeadersSerializer.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.protocol.serializer.impl;
9 |
10 | import java.util.Set;
11 |
12 | import ro.polak.http.Headers;
13 | import ro.polak.http.protocol.serializer.Serializer;
14 |
15 | /**
16 | * Serializes headers to text representation.
17 | *
18 | * @author Piotr Polak piotr [at] polak [dot] ro
19 | * @since 201611
20 | */
21 | public class HeadersSerializer implements Serializer {
22 |
23 | private static final String NEW_LINE = "\r\n";
24 | private static final String KEY_VALUE_SEPARATOR = ": ";
25 |
26 | /**
27 | * Generates string representation of headers.
28 | *
29 | * @return
30 | */
31 | @Override
32 | public String serialize(final Headers headers) {
33 | Set names = headers.keySet();
34 | StringBuilder sb = new StringBuilder();
35 | for (String name : names) {
36 | sb.append(name)
37 | .append(KEY_VALUE_SEPARATOR)
38 | .append(headers.getHeader(name))
39 | .append(NEW_LINE);
40 | }
41 | sb.append(NEW_LINE);
42 |
43 | return sb.toString();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/base/src/main/java/ro/polak/webserver/base/logic/AssetUtil.java:
--------------------------------------------------------------------------------
1 | package ro.polak.webserver.base.logic;
2 |
3 | import android.content.res.AssetManager;
4 |
5 | import java.io.File;
6 | import java.io.FileOutputStream;
7 | import java.io.IOException;
8 | import java.io.InputStream;
9 | import java.io.OutputStream;
10 |
11 | import ro.polak.http.utilities.IOUtilities;
12 |
13 | /**
14 | * Provides helper methods for managing/serving Android assets.
15 | *
16 | * @author Piotr Polak piotr [at] polak [dot] ro
17 | * @since 201709
18 | */
19 | public final class AssetUtil {
20 |
21 | private AssetUtil() {
22 |
23 | }
24 |
25 | /**
26 | * Copies asset to file.
27 | *
28 | * @param assetManager
29 | * @param assetPath
30 | * @param destination
31 | * @throws IOException
32 | */
33 | public static void copyAssetToFile(final AssetManager assetManager,
34 | final String assetPath,
35 | final File destination)
36 | throws IOException {
37 |
38 | InputStream in = null;
39 | OutputStream out = null;
40 | try {
41 | in = assetManager.open(assetPath);
42 | out = new FileOutputStream(destination);
43 | IOUtilities.copyStreams(in, out);
44 | } finally {
45 | IOUtilities.closeSilently(out);
46 | IOUtilities.closeSilently(in);
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/admin/logic/FileIconMapper.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package admin.logic;
9 |
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | /**
14 | * Maps extensions to file ICONS.
15 | */
16 | public class FileIconMapper {
17 |
18 | private static final String ICON_EXT = ".png";
19 | private static final Map ICONS = new HashMap<>();
20 |
21 | static {
22 | ICONS.put("pdf", "");
23 | ICONS.put("jpg", "");
24 | ICONS.put("jpeg", "jpg");
25 | ICONS.put("png", "");
26 | ICONS.put("zip", "");
27 | ICONS.put("gif", "");
28 | }
29 |
30 | /**
31 | * Resolves icon path. If the extension is not known, a default path is returned.
32 | *
33 | * @param extension
34 | * @return
35 | */
36 | public String getIconRelativePath(final String extension) {
37 | String ext = extension.toLowerCase();
38 |
39 | if (ICONS.containsKey(ext)) {
40 | String iconPathKey = ICONS.get(ext);
41 | if (!"".equals(iconPathKey)) {
42 | return iconPathKey + ICON_EXT;
43 | }
44 |
45 | return ext + ICON_EXT;
46 | }
47 |
48 | return "default" + ICON_EXT;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/ServerRunnableTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.io.IOException;
6 | import java.net.Socket;
7 |
8 | import ro.polak.http.configuration.ServerConfig;
9 | import ro.polak.http.errorhandler.HttpErrorHandlerResolver;
10 | import ro.polak.http.servlet.factory.HttpServletRequestImplFactory;
11 | import ro.polak.http.servlet.factory.HttpServletResponseImplFactory;
12 |
13 | import static org.mockito.Mockito.mock;
14 | import static org.mockito.Mockito.times;
15 | import static org.mockito.Mockito.verify;
16 | import static org.mockito.Mockito.when;
17 |
18 | // CHECKSTYLE.OFF: JavadocType
19 | public class ServerRunnableTest {
20 |
21 | @Test
22 | public void shouldLogIOExceptionsSilently() throws Exception {
23 |
24 | Socket socket = mock(Socket.class);
25 | HttpServletResponseImplFactory responseFactory = mock(HttpServletResponseImplFactory.class);
26 |
27 | when(responseFactory.createFromSocket(socket)).thenThrow(new IOException());
28 |
29 | ServerRunnable serverRunnable = new ServerRunnable(socket, mock(ServerConfig.class),
30 | mock(HttpServletRequestImplFactory.class),
31 | responseFactory,
32 | mock(HttpErrorHandlerResolver.class),
33 | new PathHelper()
34 | );
35 |
36 | serverRunnable.run();
37 |
38 | verify(socket, times(1)).close();
39 | }
40 | }
41 | // CHECKSTYLE.ON: JavadocType
42 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/impl/HttpError405Handler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler.impl;
9 |
10 | import java.io.IOException;
11 |
12 | import ro.polak.http.Headers;
13 | import ro.polak.http.errorhandler.AbstractHtmlErrorHandler;
14 | import ro.polak.http.servlet.HttpServletResponse;
15 |
16 | /**
17 | * 405 Method Not Allowed HTTP error handler.
18 | *
19 | * @author Piotr Polak piotr [at] polak [dot] ro
20 | * @since 201509
21 | */
22 | public class HttpError405Handler extends AbstractHtmlErrorHandler {
23 |
24 | private String allowedMethods;
25 |
26 | public HttpError405Handler(final String allowedMethods) {
27 | super(HttpServletResponse.STATUS_METHOD_NOT_ALLOWED, "Error 405 - Method Not Allowed",
28 | "The method specified in the Request-Line is not allowed for the resource "
29 | + "identified by the Request-URI.
", null);
30 | this.allowedMethods = allowedMethods;
31 | }
32 |
33 | /**
34 | * {@inheritDoc}
35 | */
36 | @Override
37 | public void serve(final HttpServletResponse response) throws IOException {
38 | response.getHeaders().setHeader(Headers.HEADER_ALLOW, allowedMethods);
39 | super.serve(response);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/Servlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | import ro.polak.http.exception.ServletException;
11 |
12 | /**
13 | * HttpServlet v3 interface, declares service() method.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 200902
17 | */
18 | public interface Servlet {
19 |
20 | /**
21 | * Initialization method that can be overwritten.
22 | *
23 | * @throws ServletException
24 | */
25 | void init() throws ServletException;
26 |
27 | /**
28 | * The servlet initialization method. The reusable resources should be
29 | * initialized in the init method.
30 | *
31 | * @param servletConfig
32 | */
33 | void init(ServletConfig servletConfig) throws ServletException;
34 |
35 | /**
36 | * Called by the container to indicate to a servlet that is is going to be taken out of service.
37 | */
38 | void destroy();
39 |
40 | /**
41 | * Called by servlet container, the main servlet logic method.
42 | */
43 | void service(HttpServletRequest request, HttpServletResponse response) throws ServletException; /* IOException */
44 |
45 | /**
46 | * Returns servlet info such as author or copyright.
47 | *
48 | * @return
49 | */
50 | String getServletInfo();
51 | }
52 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/protocol/serializer/impl/HeadersSerializerTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.protocol.serializer.impl;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import ro.polak.http.Headers;
6 | import ro.polak.http.protocol.serializer.Serializer;
7 |
8 | import static org.hamcrest.CoreMatchers.anyOf;
9 | import static org.hamcrest.CoreMatchers.is;
10 | import static org.hamcrest.MatcherAssert.assertThat;
11 |
12 | // CHECKSTYLE.OFF: JavadocType
13 | public class HeadersSerializerTest {
14 |
15 | private static Serializer headersSerializer = new HeadersSerializer();
16 |
17 | @Test
18 | public void shouldSerializeResponse() {
19 | Headers headers = new Headers();
20 | headers.setHeader("Header", "Value");
21 | headers.setHeader("SomeOtherHeader", "123");
22 |
23 | assertThat(headersSerializer.serialize(headers), anyOf(
24 | is("SomeOtherHeader: 123\r\nHeader: Value\r\n\r\n"),
25 | is("Header: Value\r\nSomeOtherHeader: 123\r\n\r\n")
26 | ));
27 | }
28 |
29 | @Test
30 | public void shouldPreserveOriginalCase() {
31 | Headers headers = new Headers();
32 | headers.setHeader("header", "Value");
33 | headers.setHeader("someOtherHeader", "123");
34 |
35 | assertThat(headersSerializer.serialize(headers), anyOf(
36 | is("someOtherHeader: 123\r\nheader: Value\r\n\r\n"),
37 | is("header: Value\r\nsomeOtherHeader: 123\r\n\r\n")
38 | ));
39 | }
40 | }
41 | // CHECKSTYLE.ON: JavadocType
42 |
--------------------------------------------------------------------------------
/app/src/main/java/admin/filter/LogoutFilter.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2018
6 | **************************************************/
7 |
8 | package admin.filter;
9 |
10 | import admin.logic.AccessControl;
11 | import ro.polak.http.configuration.ServerConfig;
12 | import ro.polak.http.servlet.Filter;
13 | import ro.polak.http.servlet.FilterChain;
14 | import ro.polak.http.servlet.FilterConfig;
15 | import ro.polak.http.servlet.HttpServletRequest;
16 | import ro.polak.http.servlet.HttpServletResponse;
17 |
18 | /**
19 | * Handles the logout logic.
20 | */
21 | public class LogoutFilter implements Filter {
22 |
23 | private FilterConfig filterConfig;
24 | private ServerConfig serverConfig;
25 |
26 | /**
27 | * {@inheritDoc}
28 | */
29 | @Override
30 | public void init(final FilterConfig filterConfig) {
31 | this.filterConfig = filterConfig;
32 | serverConfig = (ServerConfig) filterConfig.getServletContext()
33 | .getAttribute(ServerConfig.class.getName());
34 | }
35 |
36 | /**
37 | * {@inheritDoc}
38 | */
39 | @Override
40 | public void doFilter(final HttpServletRequest request, final HttpServletResponse response,
41 | final FilterChain filterChain) {
42 |
43 | new AccessControl(serverConfig, request.getSession()).logout();
44 | response.sendRedirect(filterConfig.getServletContext().getContextPath() + "/Login");
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/ServletContainer.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | import ro.polak.http.exception.FilterInitializationException;
11 | import ro.polak.http.exception.ServletException;
12 | import ro.polak.http.exception.ServletInitializationException;
13 |
14 | /**
15 | * Manages life cycle of servlets.
16 | *
17 | * @author Piotr Polak piotr [at] polak [dot] ro
18 | * @since 20170
19 | */
20 | public interface ServletContainer {
21 |
22 | /**
23 | * Returns initialized servlet for given class name.
24 | *
25 | * @param servletClass
26 | * @param servletConfig
27 | * @return
28 | * @throws ServletInitializationException
29 | * @throws ServletException
30 | */
31 | Servlet getServletForClass(Class extends HttpServlet> servletClass, ServletConfig servletConfig)
32 | throws ServletInitializationException, ServletException;
33 |
34 | /**
35 | * Returns initialized servlet for given class name.
36 | *
37 | * @param filterClass
38 | * @return
39 | * @throws FilterInitializationException
40 | */
41 | Filter getFilterForClass(Class extends Filter> filterClass, FilterConfig filterConfig)
42 | throws FilterInitializationException, ServletException;
43 |
44 | /**
45 | * Shuts down the servlet container, closes all open resources.
46 | */
47 | void shutdown();
48 | }
49 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/servlet/loader/SampleServlet.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.servlet.loader;
2 |
3 | import ro.polak.http.exception.ServletException;
4 | import ro.polak.http.servlet.HttpServlet;
5 | import ro.polak.http.servlet.HttpServletRequest;
6 | import ro.polak.http.servlet.HttpServletResponse;
7 | import ro.polak.http.servlet.ServletConfig;
8 |
9 | // CHECKSTYLE.OFF: DesignForExtension JavadocType
10 | // CHECKSTYLE.OFF: JavadocType
11 | public class SampleServlet extends HttpServlet {
12 |
13 | private int initializedCounter = 0;
14 | private int destroyedCounter = 0;
15 |
16 | private ServletConfig servletConfig;
17 |
18 | @Override
19 | public void init(final ServletConfig servletConfig) throws ServletException {
20 | this.servletConfig = servletConfig;
21 | init();
22 | }
23 |
24 | @Override
25 | public void init() throws ServletException {
26 | super.init();
27 | initializedCounter++;
28 | }
29 |
30 | @Override
31 | public void destroy() {
32 | super.destroy();
33 | destroyedCounter++;
34 | }
35 |
36 | @Override
37 | public void service(final HttpServletRequest request, final HttpServletResponse response) {
38 | // Do nothing, this is used for test only
39 | }
40 |
41 | public int getInitializedCounter() {
42 | return initializedCounter;
43 | }
44 |
45 | public int getDestroyedCounter() {
46 | return destroyedCounter;
47 | }
48 |
49 | public ServletConfig getServletConfig() {
50 | return servletConfig;
51 | }
52 | }
53 | // CHECKSTYLE.ON: JavadocType
54 | // CHECKSTYLE.ON: DesignForExtension
55 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/utilities/FileUtilitiesTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.utilities;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import static org.hamcrest.MatcherAssert.assertThat;
6 | import static org.hamcrest.Matchers.is;
7 | import static org.hamcrest.Matchers.nullValue;
8 | import static ro.polak.http.ExtraMarchers.utilityClass;
9 |
10 | // CHECKSTYLE.OFF: JavadocType
11 | public class FileUtilitiesTest {
12 |
13 | @Test
14 | public void shouldNotBeInstantiableFinalClass() {
15 | assertThat(FileUtilities.class, is(utilityClass()));
16 | }
17 |
18 | @Test
19 | public void shouldReturnValidExtension() {
20 | assertThat(FileUtilities.getExtension("file.ext"), is("ext"));
21 | assertThat(FileUtilities.getExtension("/path/file.ext"), is("ext"));
22 | assertThat(FileUtilities.getExtension("file"), is(""));
23 | assertThat(FileUtilities.getExtension(null), is(nullValue()));
24 | }
25 |
26 | // CHECKSTYLE.OFF: MagicNumber
27 | @Test
28 | public void shouldFormatFileSize() {
29 | assertThat(FileUtilities.fileSizeUnits(1), is("1 B"));
30 | assertThat(FileUtilities.fileSizeUnits(1024), is("1.00 KB"));
31 | assertThat(FileUtilities.fileSizeUnits(1025), is("1.00 KB"));
32 | assertThat(FileUtilities.fileSizeUnits(1048576), is("1.00 MB"));
33 | assertThat(FileUtilities.fileSizeUnits(1048577), is("1.00 MB"));
34 | assertThat(FileUtilities.fileSizeUnits(1073741824), is("1.00 GB"));
35 | assertThat(FileUtilities.fileSizeUnits(1073741825), is("1.00 GB"));
36 | }
37 | // CHECKSTYLE.OFF: MagicNumber
38 | }
39 | // CHECKSTYLE.ON: JavadocType
40 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/HttpServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | import ro.polak.http.exception.ServletException;
11 |
12 | /**
13 | * Default abstract servlet.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @since 200802
17 | */
18 | public abstract class HttpServlet implements Servlet {
19 |
20 | private ServletConfig servletConfig;
21 |
22 | /**
23 | * {@inheritDoc}
24 | */
25 | @Override
26 | public void init(final ServletConfig servletConfig) throws ServletException {
27 | this.servletConfig = servletConfig;
28 | init();
29 | }
30 |
31 | /**
32 | * {@inheritDoc}
33 | */
34 | @Override
35 | public void init() throws ServletException {
36 | // To be overwritten
37 | }
38 |
39 | /**
40 | * {@inheritDoc}
41 | */
42 | @Override
43 | public void destroy() {
44 | // Empty by default, should be overwritten by the implementing servlet
45 | }
46 |
47 | /**
48 | * {@inheritDoc}
49 | */
50 | @Override
51 | public String getServletInfo() {
52 | return "";
53 | }
54 |
55 | /**
56 | * Returns servlet context.
57 | *
58 | * @return
59 | */
60 | public ServletContext getServletContext() {
61 | if (servletConfig == null) {
62 | return null;
63 | }
64 | return servletConfig.getServletContext();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/servlet/impl/HttpServletResponseImplIT.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.servlet.impl;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import java.io.BufferedReader;
6 | import java.io.IOException;
7 | import java.io.InputStreamReader;
8 | import java.io.OutputStream;
9 | import java.net.Socket;
10 |
11 | import ro.polak.http.AbstractIT;
12 | import ro.polak.http.RequestBuilder;
13 |
14 | import static org.hamcrest.CoreMatchers.startsWith;
15 | import static org.hamcrest.MatcherAssert.assertThat;
16 | import static org.junit.jupiter.api.Assertions.fail;
17 |
18 | // CHECKSTYLE.OFF: JavadocType
19 | public class HttpServletResponseImplIT extends AbstractIT {
20 |
21 | @Test
22 | public void shouldPrintHeadersFirstWhenWritingToOutputStream() throws IOException {
23 | String requestBody = RequestBuilder.defaultBuilder()
24 | .get("/example/Streaming")
25 | .withCloseConnection()
26 | .toString();
27 |
28 | Socket socket = getSocket();
29 | OutputStream out = socket.getOutputStream();
30 | out.write(requestBody.getBytes());
31 | BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
32 |
33 | String line;
34 | int numberOfLinesRead = 0;
35 | while ((line = in.readLine()) != null) {
36 | if (++numberOfLinesRead == 1) {
37 | assertThat(line, startsWith("HTTP/1.1 200"));
38 | }
39 | }
40 |
41 | if (numberOfLinesRead == 0) {
42 | fail("No server response was read");
43 | }
44 |
45 | socket.close();
46 | }
47 | }
48 | // CHECKSTYLE.ON: JavadocType
49 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/configuration/impl/FilterMappingImpl.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2018-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.configuration.impl;
9 |
10 | import java.util.regex.Pattern;
11 |
12 | import ro.polak.http.configuration.FilterMapping;
13 | import ro.polak.http.servlet.Filter;
14 |
15 | /**
16 | * Default implementation for FilterMapping.
17 | *
18 | * @author Piotr Polak piotr [at] polak [dot] ro
19 | * @since 201803
20 | */
21 | public class FilterMappingImpl implements FilterMapping {
22 |
23 | private final Pattern urlPattern;
24 | private final Pattern urlExcludePattern;
25 | private final Class extends Filter> filterClass;
26 |
27 | public FilterMappingImpl(final Pattern urlPattern,
28 | final Pattern urlExcludePattern,
29 | final Class extends Filter> filterClass) {
30 | this.urlPattern = urlPattern;
31 | this.urlExcludePattern = urlExcludePattern;
32 | this.filterClass = filterClass;
33 | }
34 |
35 | /**
36 | * {@inheritDoc}
37 | */
38 | @Override
39 | public Pattern getUrlPattern() {
40 | return urlPattern;
41 | }
42 |
43 | /**
44 | * {@inheritDoc}
45 | */
46 | @Override
47 | public Pattern getUrlExcludePattern() {
48 | return urlExcludePattern;
49 | }
50 |
51 | /**
52 | * {@inheritDoc}
53 | */
54 | @Override
55 | public Class extends Filter> getFilterClass() {
56 | return filterClass;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/configuration/ServletMappingBuilder.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2018-2018
6 | **************************************************/
7 |
8 | package ro.polak.http.configuration;
9 |
10 | import java.util.regex.Pattern;
11 |
12 | import ro.polak.http.configuration.impl.ServletMappingImpl;
13 | import ro.polak.http.servlet.HttpServlet;
14 |
15 | /**
16 | * Utility for building servlet mapping configuration.
17 | *
18 | * @author Piotr Polak piotr [at] polak [dot] ro
19 | * @since 201803
20 | */
21 | public final class ServletMappingBuilder {
22 |
23 | private final ServletContextBuilder servletContextBuilder;
24 | private Pattern urlPattern;
25 | private Class extends HttpServlet> servletClass;
26 |
27 | /**
28 | * Created a mapping builder. This constructor should be package scoped.
29 | *
30 | * @param servletContextBuilder
31 | */
32 | ServletMappingBuilder(final ServletContextBuilder servletContextBuilder) {
33 | this.servletContextBuilder = servletContextBuilder;
34 | }
35 |
36 | public ServletMappingBuilder withUrlPattern(final Pattern urlPattern) {
37 | this.urlPattern = urlPattern;
38 | return this;
39 | }
40 |
41 | public ServletMappingBuilder withServletClass(final Class extends HttpServlet> servletClass) {
42 | this.servletClass = servletClass;
43 | return this;
44 | }
45 |
46 | public ServletContextBuilder end() {
47 | servletContextBuilder.withServletMapping(new ServletMappingImpl(urlPattern, servletClass));
48 | return servletContextBuilder;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/errorhandler/AbstractPlainTextHttpErrorHandler.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package ro.polak.http.errorhandler;
9 |
10 | import java.io.IOException;
11 |
12 | import ro.polak.http.servlet.HttpServletResponse;
13 | import ro.polak.http.servlet.impl.HttpServletResponseImpl;
14 |
15 | /**
16 | * Abstract Http Error Handler.
17 | *
18 | * @author Piotr Polak piotr [at] polak [dot] ro
19 | * @since 201701
20 | */
21 | public abstract class AbstractPlainTextHttpErrorHandler implements HttpErrorHandler {
22 |
23 | private final String status;
24 | private final String message;
25 |
26 | public AbstractPlainTextHttpErrorHandler(final String status, final String message) {
27 | this.status = status;
28 | this.message = message;
29 | }
30 |
31 | /**
32 | * {@inheritDoc}
33 | */
34 | @Override
35 | public void serve(final HttpServletResponse response) throws IOException {
36 | response.setStatus(status);
37 | response.setContentType("text/plain");
38 | response.setContentLength(message.length());
39 | response.getWriter().write(message);
40 | ((HttpServletResponseImpl) response).flush();
41 | }
42 |
43 | /**
44 | * Returns status message.
45 | * @return
46 | */
47 | protected String getStatus() {
48 | return status;
49 | }
50 |
51 | /**
52 | * Returns the message content.
53 | * @return
54 | */
55 | protected String getMessage() {
56 | return message;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/http/src/test/java/ro/polak/http/servlet/HttpServletTest.java:
--------------------------------------------------------------------------------
1 | package ro.polak.http.servlet;
2 |
3 | import org.junit.jupiter.api.Test;
4 |
5 | import ro.polak.http.exception.ServletException;
6 | import ro.polak.http.servlet.impl.ServletConfigImpl;
7 |
8 | import static org.hamcrest.CoreMatchers.equalTo;
9 | import static org.hamcrest.CoreMatchers.nullValue;
10 | import static org.hamcrest.MatcherAssert.assertThat;
11 | import static org.hamcrest.core.Is.is;
12 | import static org.mockito.Mockito.mock;
13 |
14 | // CHECKSTYLE.OFF: JavadocType
15 | public class HttpServletTest {
16 |
17 | @Test
18 | public void shouldProvideDefaultValues() {
19 | HttpServlet httpServlet = new SampleServlet();
20 | assertThat(httpServlet.getServletInfo(), is(""));
21 | assertThat(httpServlet.getServletContext(), is(nullValue()));
22 | httpServlet.destroy();
23 | }
24 |
25 | @Test
26 | public void shouldProvideContextAfterInitialization() throws ServletException {
27 | HttpServlet httpServlet = new SampleServlet();
28 | ServletContext servletContext = mock(ServletContext.class);
29 | ServletConfig servletConfig = new ServletConfigImpl(servletContext);
30 | httpServlet.init(servletConfig);
31 | assertThat(httpServlet.getServletInfo(), is(""));
32 | assertThat(httpServlet.getServletContext(), is(equalTo(servletContext)));
33 | httpServlet.destroy();
34 | }
35 |
36 | private class SampleServlet extends HttpServlet {
37 | @Override
38 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
39 | // Do nothing, this is just a test servlet
40 | }
41 | }
42 | }
43 | // CHECKSTYLE.ON: JavadocType
44 |
--------------------------------------------------------------------------------
/app/src/main/java/admin/IndexServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2017
6 | **************************************************/
7 |
8 | package admin;
9 |
10 | import admin.logic.HTMLDocument;
11 | import ro.polak.http.exception.ServletException;
12 | import ro.polak.http.servlet.HttpServlet;
13 | import ro.polak.http.servlet.HttpServletRequest;
14 | import ro.polak.http.servlet.HttpServletResponse;
15 |
16 | /**
17 | * Admin panel front page.
18 | */
19 | public class IndexServlet extends HttpServlet {
20 |
21 | /**
22 | * {@inheritDoc}
23 | */
24 | @Override
25 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
26 | HTMLDocument doc = renderDocument();
27 | response.getWriter().print(doc.toString());
28 | }
29 |
30 | private HTMLDocument renderDocument() {
31 | HTMLDocument doc = new HTMLDocument("About");
32 | doc.setOwnerClass(getClass().getSimpleName());
33 |
34 | doc.writeln("");
35 | doc.write("" + ro.polak.http.WebServer.SIGNATURE + " running.
");
36 | doc.write("Small multithread web server written completely in Java SE. ");
37 | doc.write("Implements most of the HTTP 1.1 specification. Uses JLWS Servlets for handling dynamic pages. ");
38 | doc.write("Supports cookies, sessions, file uploads.
");
39 | doc.write("Written by Piotr Polak. Visit homepage.
");
41 | return doc;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/http/src/main/java/example/ChunkedWithDelayServlet.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package example;
9 |
10 | import java.io.PrintWriter;
11 |
12 | import ro.polak.http.exception.ServletException;
13 | import ro.polak.http.servlet.HttpServlet;
14 | import ro.polak.http.servlet.HttpServletRequest;
15 | import ro.polak.http.servlet.HttpServletResponse;
16 |
17 | import static ro.polak.http.Headers.HEADER_TRANSFER_ENCODING;
18 |
19 | /**
20 | * Chunked transfer with delay example.
21 | */
22 | public class ChunkedWithDelayServlet extends HttpServlet {
23 |
24 | private static final int CHUNKS_COUNT = 100;
25 | private static final int SLEEP_LENGTH_IN_MS = 30;
26 |
27 | /**
28 | * {@inheritDoc}
29 | */
30 | @Override
31 | public void service(final HttpServletRequest request, final HttpServletResponse response) throws ServletException {
32 | response.getHeaders().setHeader(HEADER_TRANSFER_ENCODING, "chunked");
33 | PrintWriter printWriter = response.getWriter();
34 | printWriter.println("");
35 | printWriter.println(" | ");
36 | for (int i = 0; i < CHUNKS_COUNT; i++) {
37 | try {
38 | Thread.sleep(SLEEP_LENGTH_IN_MS);
39 | } catch (InterruptedException e) {
40 | }
41 | printWriter.println(" | ");
42 | printWriter.flush();
43 | }
44 | printWriter.println("
|
");
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/servlet/ChunkedPrintWriter.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.servlet;
9 |
10 | import java.io.OutputStream;
11 |
12 | /**
13 | * Allows flushing buffer in chunks.
14 | *
15 | * @author Piotr Polak piotr [at] polak [dot] ro
16 | * @see Chunked transfer encoding
17 | * @since 201010
18 | */
19 | public class ChunkedPrintWriter extends ServletPrintWriter {
20 |
21 | // TODO Move this capability to the ServletOutputStreamImpl
22 |
23 | private static final String NEW_LINE = "\r\n";
24 | private static final String END_LINE = "0\r\n\r\n";
25 |
26 | /**
27 | * Default constructor.
28 | *
29 | * @param out
30 | */
31 | public ChunkedPrintWriter(final OutputStream out) {
32 | super(out);
33 | }
34 |
35 | /**
36 | * {@inheritDoc}
37 | */
38 | @Override
39 | public void println() {
40 | // Overwrites the original new line character
41 | synchronized (lock) {
42 | print(NEW_LINE);
43 | }
44 | }
45 |
46 | /**
47 | * {@inheritDoc}
48 | */
49 | @Override
50 | public void write(final String str) {
51 | String head = Long.toHexString(str.length()).toUpperCase() + NEW_LINE;
52 | super.write(head);
53 | super.write(str);
54 | super.write(NEW_LINE);
55 | }
56 |
57 | /**
58 | * Writes the end of chunked message.
59 | */
60 | @Override
61 | public void writeEnd() {
62 | super.writeEnd();
63 | super.write(END_LINE);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/app/src/main/java/api/logic/APIResponse.java:
--------------------------------------------------------------------------------
1 | package api.logic;
2 |
3 | import org.json.JSONArray;
4 | import org.json.JSONException;
5 | import org.json.JSONObject;
6 |
7 | /**
8 | * Represents JSON API Response.
9 | */
10 | public class APIResponse {
11 |
12 | public static final String MEDIA_TYPE_APPLICATION_JSON = "application/json";
13 | public static final int CODE_OK = 200;
14 | public static final int CODE_ERROR = 400;
15 | private static final String ATTR_STATUS = "status";
16 | private static final String ATTR_MESSAGE = "message";
17 | private static final String ATTR_RESULT = "result";
18 | private static final String MESSAGE_OK = "OK";
19 |
20 | private JSONObject jsonObject = new JSONObject();
21 |
22 | /**
23 | * Serializes API Response.
24 | *
25 | * @param code
26 | * @param message
27 | * @param result
28 | * @throws JSONException
29 | */
30 | public APIResponse(final int code, final String message, final JSONArray result) throws JSONException {
31 | jsonObject.put(ATTR_STATUS, code);
32 | jsonObject.put(ATTR_MESSAGE, message);
33 | jsonObject.put(ATTR_RESULT, result);
34 | }
35 |
36 | /**
37 | * Serializes API Response.
38 | *
39 | * @throws JSONException
40 | */
41 | public APIResponse() throws JSONException {
42 | this(CODE_OK, MESSAGE_OK, null);
43 | }
44 |
45 | /**
46 | * Serializes API Response.
47 | *
48 | * @param code
49 | * @param message
50 | * @throws JSONException
51 | */
52 | public APIResponse(final int code, final String message) throws JSONException {
53 | this(code, message, null);
54 | }
55 |
56 | /**
57 | * Returns object marshalled to JSON.
58 | *
59 | * @return
60 | */
61 | @Override
62 | public String toString() {
63 | return jsonObject.toString();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/MultipartHeadersPart.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2008-2016
6 | **************************************************/
7 |
8 | package ro.polak.http;
9 |
10 | /**
11 | * Multipart request headers (for each multipart).
12 | *
13 | * @author Piotr Polak piotr [at] polak [dot] ro
14 | * @link http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
15 | * @since 200802
16 | */
17 | public class MultipartHeadersPart {
18 |
19 | private String fileName;
20 | private String contentType;
21 | private String name;
22 |
23 | /**
24 | * Returns the uploaded file name.
25 | *
26 | * @return
27 | */
28 | public String getFileName() {
29 | return fileName;
30 | }
31 |
32 | /**
33 | * Returns the content type of the uploaded file.
34 | *
35 | * @return
36 | */
37 | public String getContentType() {
38 | return contentType;
39 | }
40 |
41 | /**
42 | * Returns the name of the form post field.
43 | *
44 | * @return
45 | */
46 | public String getName() {
47 | return name;
48 | }
49 |
50 | /**
51 | * Sets the uploaded file name.
52 | *
53 | * @param fileName
54 | */
55 | public void setFileName(final String fileName) {
56 | this.fileName = fileName;
57 | }
58 |
59 | /**
60 | * Sets the content type of the uploaded file.
61 | *
62 | * @param contentType
63 | */
64 | public void setContentType(final String contentType) {
65 | this.contentType = contentType;
66 | }
67 |
68 | /**
69 | * Sets the name of the form post field.
70 | *
71 | * @param name
72 | */
73 | public void setName(final String name) {
74 | this.name = name;
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/http/src/main/java/ro/polak/http/protocol/parser/impl/QueryStringParser.java:
--------------------------------------------------------------------------------
1 | /**************************************************
2 | * Android Web Server
3 | * Based on JavaLittleWebServer (2008)
4 | *
5 | * Copyright (c) Piotr Polak 2016-2016
6 | **************************************************/
7 |
8 | package ro.polak.http.protocol.parser.impl;
9 |
10 | import java.util.HashMap;
11 | import java.util.Map;
12 |
13 | import ro.polak.http.protocol.parser.MalformedInputException;
14 | import ro.polak.http.protocol.parser.Parser;
15 | import ro.polak.http.utilities.StringUtilities;
16 |
17 | /**
18 | * HTTP request headers wrapper.
19 | *
20 | * @author Piotr Polak piotr [at] polak [dot] ro
21 | * @since 201609
22 | */
23 | public class QueryStringParser implements Parser