Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Splitting library to remove dependency of Windows.Storage #227

Merged
merged 5 commits into from
Oct 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 45 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
| Component | Build Status | NuGet Package |
|:-|---|---|
| nanoFramework.WebServer | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.WebServer/_apis/build/status/nanoFramework.WebServer?repoName=nanoframework%2FnanoFramework.WebServer&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.WebServer/_build/latest?definitionId=65&repoName=nanoframework%2FnanoFramework.WebServer&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.WebServer.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.WebServer/) |
| nanoFramework.WebServer.FileSystem | [![Build Status](https://dev.azure.com/nanoframework/nanoFramework.WebServer/_apis/build/status/nanoFramework.WebServer?repoName=nanoframework%2FnanoFramework.WebServer&branchName=main)](https://dev.azure.com/nanoframework/nanoFramework.WebServer/_build/latest?definitionId=65&repoName=nanoframework%2FnanoFramework.WebServer&branchName=main) | [![NuGet](https://img.shields.io/nuget/v/nanoFramework.WebServer.FileSystem.svg?label=NuGet&style=flat&logo=nuget)](https://www.nuget.org/packages/nanoFramework.WebServer.FileSystem/) |

## .NET nanoFramework WebServer

This library was coded by [Laurent Ellerbach](@Ellerbach) who generously offered it to the .NET **nanoFramework** project.
This library was coded by [Laurent Ellerbach](https://github.com/Ellerbach) who generously offered it to the .NET **nanoFramework** project.

This is a simple nanoFramework WebServer. Features:

- Handle multi-thread requests
- Serve static files on any storage
- Serve static files from any storage using [`nanoFramework.WebServer.FileSystem` NuGet](https://www.nuget.org/packages/nanoFramework.WebServer.FileSystem). Requires a target device with support for storage (having `System.IO.FileSystem` capability).
- Handle parameter in URL
- Possible to have multiple WebServer running at the same time
- supports GET/PUT and any other word
Expand All @@ -31,6 +32,7 @@ This is a simple nanoFramework WebServer. Features:
- [URL decode/encode](https://github.com/nanoframework/lib-nanoFramework.System.Net.Http/blob/develop/nanoFramework.System.Net.Http/Http/System.Net.HttpUtility.cs)

Limitations:

- Does not support any zip in the request or response stream

## Usage
Expand Down Expand Up @@ -93,9 +95,10 @@ The `RouteAnyTest`is called whenever the url is `test/any` whatever the method i

There is a more advance example with simple REST API to get a list of Person and add a Person. Check it in the [sample](./WebServer.Sample/ControllerPerson.cs).

**Important**
* By default the routes are not case sensitive and the attribute **must** be lowercase
* If you want to use case sensitive routes like in the previous example, use the attribute `CaseSensitive`. As in the previous example, you **must** write the route as you want it to be responded to.
> [!Important]
>
> By default the routes are not case sensitive and the attribute **must** be lowercase.
> If you want to use case sensitive routes like in the previous example, use the attribute `CaseSensitive`. As in the previous example, you **must** write the route as you want it to be responded to.

## A simple GPIO controller REST API

Expand All @@ -113,13 +116,13 @@ You will find in simple [GPIO controller sample](https://github.com/nanoframewor
Controllers support authentication. 3 types of authentications are currently implemented on controllers only:

- Basic: the classic user and password following the HTTP standard. Usage:
- `[Authentication("Basic")]` will use the default credential of the webserver
- `[Authentication("Basic:myuser mypassword")]` will use myuser as a user and my password as a password. Note: the user cannot contains spaces.
- `[Authentication("Basic")]` will use the default credential of the webserver
- `[Authentication("Basic:myuser mypassword")]` will use myuser as a user and my password as a password. Note: the user cannot contains spaces.
- APiKey in header: add ApiKey in headers with the API key. Usage:
- `[Authentication("ApiKey")]` will use the default credential of the webserver
- `[Authentication("ApiKeyc:akey")]` will use akey as ApiKey.
- `[Authentication("ApiKey")]` will use the default credential of the webserver
- `[Authentication("ApiKeyc:akey")]` will use akey as ApiKey.
- None: no authentication required. Usage:
- `[Authentication("None")]` will use the default credential of the webserver
- `[Authentication("None")]` will use the default credential of the webserver

The Authentication attribute applies to both public Classes an public Methods.

Expand Down Expand Up @@ -184,9 +187,9 @@ using (WebServer server = new WebServer(80, HttpProtocol.Http, new Type[] { type
With the previous example the following happens:

- All the controller by default, even when nothing is specified will use the controller credentials. In our case, the Basic authentication with the default user (topuser) and password (topPassword) will be used.
- When calling http://yoururl/authbasic from a browser, you will be prompted for the user and password, use the default one topuser and topPassword to get access
- When calling http://yoururl/authnone, you won't be prompted because the authentication has been overridden for no authentication
- When calling http://yoururl/authbasicspecial, the user and password are different from the defautl ones, user2 and password is the right couple here
- When calling http://yoururl/authbasic from a browser, you will be prompted for the user and password, use the default one topuser and topPassword to get access
- When calling http://yoururl/authnone, you won't be prompted because the authentication has been overridden for no authentication
- When calling http://yoururl/authbasicspecial, the user and password are different from the defautl ones, user2 and password is the right couple here
- If you would have define in the controller a specific user and password like `[Authentication("Basic:myuser mypassword")]`, then the default one for all the controller would have been myuser and mypassword
- When calling http://yoururl/authapi, you must pass the header `ApiKey` (case sensitive) with the value `superKey1234` to get authorized, this is overridden the default Basic authentication
- When calling http://yoururl/authdefaultapi, the default key `ATopSecretAPIKey1234` will be used so you have to pass it in the headers of the request
Expand Down Expand Up @@ -246,19 +249,42 @@ if (url.ToLower().IndexOf("/param.htm") == 0)
And server static files:

```csharp
var files = storage.GetFiles();
foreach (var file in files)
// E = USB storage
// D = SD Card
// I = Internal storage
// Adjust this based on your configuration
const string DirectoryPath = "I:\\";
string[] _listFiles;

// Gets the list of all files in a specific directory
// See the MountExample for more details if you need to mount an SD card and adjust here
// https://github.com/nanoframework/Samples/blob/main/samples/System.IO.FileSystem/MountExample/Program.cs
_listFiles = Directory.GetFiles(DirectoryPath);
// Remove the root directory
for (int i = 0; i < _listFiles.Length; i++)
{
if (file.Name == url)
_listFiles[i] = _listFiles[i].Substring(DirectoryPath.Length);
}

var fileName = url.Substring(1);
// Note that the file name is case sensitive
// Very simple example serving a static file on an SD card
foreach (var file in _listFiles)
{
if (file == fileName)
{
WebServer.SendFileOverHTTP(e.Context.Response, file);
WebServer.SendFileOverHTTP(e.Context.Response, DirectoryPath + file);
return;
}
}

WebServer.OutputHttpCode(e.Context.Response, HttpStatusCode.NotFound);
```

> [!Important]
>
> Serving files requires the `nanoFramework.WebServer.FileSystem` nuget **AND** that the device supports storage so `System.IO.FileSystem`.

And also **REST API** is supported, here is a comprehensive example:

```csharp
Expand Down Expand Up @@ -363,7 +389,8 @@ using (WebServer server = new WebServer(443, HttpProtocol.Https)
}
```

> IMPORTANT: because the certificate above is not issued from a Certificate Authority it won't be recognized as a valid certificate. If you want to access the nanoFramework device with your browser, for example, you'll have to add the (CRT file)[WebServer.Sample\webserver-cert.crt] as a trusted one. On Windows, you just have to double click on the CRT file and then click "Install Certificate...".
> [!IMPORTANT]
> Because the certificate above is not issued from a Certificate Authority it won't be recognized as a valid certificate. If you want to access the nanoFramework device with your browser, for example, you'll have to add the [CRT file](WebServer.Sample\webserver-cert.crt) as a trusted one. On Windows, you just have to double click on the CRT file and then click "Install Certificate...".

You can of course use the routes as defined earlier. Both will work, event or route with the notion of controller.

Expand Down
38 changes: 37 additions & 1 deletion azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,46 @@ steps:

# step from template @ nf-tools repo
# all build, update and publish steps
- template: azure-pipelines-templates/class-lib-build.yml@templates
- template: azure-pipelines-templates/class-lib-build-only.yml@templates
parameters:
sonarCloudProject: 'nanoframework_lib-nanoframework.WebServer'

# build the 2 libs step
- template: azure-pipelines-templates/class-lib-package.yml@templates
parameters:
nugetPackageName: 'nanoFramework.WebServer'

- template: azure-pipelines-templates/class-lib-package.yml@templates
parameters:
nugetPackageName: 'nanoFramework.WebServer.FileSystem'

# publish the 2 libs
- template: azure-pipelines-templates/class-lib-publish.yml@templates

# create GitHub release build from main branch
- task: GithubRelease@1
condition: >-
and(
succeeded(),
eq(variables['System.PullRequest.PullRequestId'], ''),
startsWith(variables['Build.SourceBranch'], 'refs/heads/main'),
not(contains(variables['Build.SourceBranch'], 'preview')),
eq(variables['StartReleaseCandidate'], false)
)
displayName: Create/Update GitHub release
inputs:
action: edit
gitHubConnection: 'github.com_nano-$(System.TeamProject)'
tagSource: userSpecifiedTag
tag: v$(MY_NUGET_VERSION)
title: '$(nugetPackageName) Library v$(MY_NUGET_VERSION)'
releaseNotesSource: inline
releaseNotesInline: 'Check the [changelog]($(Build.Repository.Uri)/blob/$(Build.SourceBranchName)/CHANGELOG.md).<br><br><h4>Install from NuGet</h4><br>The following NuGet packages are available for download from this release:<br>:package: [nanoFramework.WebServer](https://www.nuget.org/packages/$(nugetPackageName)/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION).<br>:package: [nanoFramework.WebServer.FileSystem (requires support of storage through System.IO.FileSystem)](https://www.nuget.org/packages/nanoFramework.WebServer.FileSystem/$(MY_NUGET_VERSION)) v$(MY_NUGET_VERSION)'
assets: '$(Build.ArtifactStagingDirectory)/*.nupkg'
assetUploadMode: replace
isPreRelease: false
addChangeLog: false

# step from template @ nf-tools repo
# report error
- template: azure-pipelines-templates/discord-webhook-task.yml@templates
Expand Down
File renamed without changes.
38 changes: 38 additions & 0 deletions nanoFramework.WebServer.FileSystem.nuspec
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2012/06/nuspec.xsd">
<metadata>
<id>nanoFramework.WebServer.FileServer</id>
<title>nanoFramework.WebServer.FileServer</title>
<version>$version$</version>
<authors>Laurent Ellerbach,nanoframework</authors>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<license type="file">LICENSE.md</license>
<releaseNotes>
</releaseNotes>
<readme>docs\README.md</readme>
<developmentDependency>false</developmentDependency>
<projectUrl>https://github.com/nanoframework/nanoFramework.WebServer</projectUrl>
<icon>images\nf-logo.png</icon>
<repository type="git" url="https://github.com/nanoframework/nanoFramework.WebServer" commit="$commit$" />
<copyright>Copyright (c) .NET Foundation and Contributors</copyright>
<description>This is a simple multithread WebServer supporting simple controller and event based calls.
Perfect for .NET nanoFramework REST API based project. Support all type of Http Methods.
Perfect for simple embedded web pages, with Support of file on a storage (USB, SD Card, in Memory).
Supports both HTTPS and HTTP.
Use this version if you want to serve local files and have support for System.IO.FileSystem on your device.
Otherwise use 'nanoFramework.WebServer' nuget.</description>
<tags>http https webserver net netmf nf nanoframework</tags>
<dependencies>
<dependency id="nanoFramework.CoreLibrary" version="1.14.2" />
<dependency id="nanoFramework.System.Net.Http.Server" version="1.5.104" />
<dependency id="nanoFramework.System.IO.FileSystem" version="1.1.23" />
</dependencies>
</metadata>
<files>
<file src="nanoFramework.WebServer\bin\Release\nanoFramework.WebServer.*" target="lib" />
<file src="assets\readme.txt" target="" />
<file src="README.md" target="docs\" />
<file src="assets\nf-logo.png" target="images" />
<file src="LICENSE.md" target="" />
</files>
</package>
18 changes: 18 additions & 0 deletions nanoFramework.WebServer.FileSystem/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;

// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("nanoFramework.WebServer")]
[assembly: AssemblyCompany("nanoFramework Contributors")]
[assembly: AssemblyProduct("nanoFramework.WebServer.FileSystem")]
[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")]


// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]

Loading