Skip to content

Commit

Permalink
Merge pull request #1332 from mdaneri/Minor_doc_fixes
Browse files Browse the repository at this point in the history
Adds documentation for CORS; Adds missing features to the Feature List; Updates Known Issues for PowerShell classes with PS7.4's SafeThread support; Splits OpenAPI documentation into multiple pages
  • Loading branch information
Badgerati authored Jul 9, 2024
2 parents 473123b + 4a3c037 commit 69790e7
Show file tree
Hide file tree
Showing 17 changed files with 1,221 additions and 1,071 deletions.
20 changes: 15 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,16 @@

Pode is a Cross-Platform framework for creating web servers to host [REST APIs](https://badgerati.github.io/Pode/Tutorials/Routes/Overview/), [Web Pages](https://badgerati.github.io/Pode/Tutorials/Routes/Examples/WebPages/), and [SMTP/TCP](https://badgerati.github.io/Pode/Servers/) Servers. Pode also allows you to render dynamic files using [`.pode`](https://badgerati.github.io/Pode/Tutorials/Views/Pode/) files, which are just embedded PowerShell, or other [Third-Party](https://badgerati.github.io/Pode/Tutorials/Views/ThirdParty/) template engines. Plus many more features, including [Azure Functions](https://badgerati.github.io/Pode/Hosting/AzureFunctions/) and [AWS Lambda](https://badgerati.github.io/Pode/Hosting/AwsLambda/) support!

<p align="center">
<img src="https://github.com/Badgerati/Pode/blob/develop/images/example_code_readme.svg?raw=true" width="70%" />
</p>
```powershell
Start-PodeServer -ScriptBlock {
Add-PodeEndPoint -Address localhost -port 32005 -Protocol Http
Add-PodeRoute -Method Get -Path '/ping' -ScriptBlock {
Write-PodeJsonResponse -Value @{value = 'pong' }
}
}
```

See [here](https://badgerati.github.io/Pode/Getting-Started/FirstApp) for building your first app! Don't know HTML, CSS, or JavaScript? No problem! [Pode.Web](https://github.com/Badgerati/Pode.Web) is currently a work in progress, and lets you build web pages using purely PowerShell!

Expand All @@ -49,8 +56,9 @@ Then navigate to `http://127.0.0.1:8000` in your browser.
* Cross-platform using PowerShell Core (with support for PS5)
* Docker support, including images for ARM/Raspberry Pi
* Azure Functions, AWS Lambda, and IIS support
* OpenAPI, Swagger, and ReDoc support
* Listen on a single or multiple IP address/hostnames
* OpenAPI specification version 3.0.x and 3.1.0
* OpenAPI documentation with Swagger, Redoc, RapidDoc, StopLight, OpenAPI-Explorer and RapiPdf
* Listen on a single or multiple IP(v4/v6) address/hostnames
* Cross-platform support for HTTP(S), WS(S), SSE, SMTP(S), and TCP(S)
* Host REST APIs, Web Pages, and Static Content (with caching)
* Support for custom error pages
Expand All @@ -73,6 +81,8 @@ Then navigate to `http://127.0.0.1:8000` in your browser.
* Support for File Watchers
* In-memory caching, with optional support for external providers (such as Redis)
* (Windows) Open the hosted server as a desktop application
* FileBrowsing support
* Localization (i18n) in Arabic, German, Spanish, France, Italian, Japanese, Korean, Polish, Portuguese, and Chinese

## 📦 Install

Expand Down
10 changes: 10 additions & 0 deletions docs/Getting-Started/FirstApp.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,16 @@ Success, saved package.json
Import-Module -Name Pode -MaximumVersion 2.99.99
```

* To ensure that any errors during the import process are caught and handled appropriately, use a try-catch block:

```powershell
try {
Import-Module -Name 'Pode' -MaximumVersion 2.99.99 -ErrorAction Stop
} catch {
# exception management code
}
```

* Within your `server.ps1` file, first you need to start the Server. This is where the main script will go that defines how the server should function:

```powershell
Expand Down
25 changes: 21 additions & 4 deletions docs/Getting-Started/KnownIssues.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,30 @@ New-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Services\HTTP\Parameters'
## PowerShell Classes

Pode uses Runspaces to deal with multithreading and other background tasks. Due to this, PowerShell classes do not work as intended and are unsafe to use.
Pode utilizes Runspaces for multithreading and other background tasks, which makes PowerShell classes behave unpredictably and renders them unsafe to use. This is primarily because an instance of a class created in one Runspace will always be marshaled back to the original Runspace whenever it is accessed again, potentially causing Routes and Middleware to become contaminated.

You can find more information about this issue [here on PowerShell](https://github.com/PowerShell/PowerShell/issues/3651).
For more details on this issue, you can refer to the [PowerShell GitHub issue](https://github.com/PowerShell/PowerShell/issues/3651).

The crux of the issue is that if you create an instance of a class in one Runspace, then every time you try to use that instance again it will always be marshaled back to the original Runspace. This means Routes and Middleware can become contaminated.
To avoid these problems, it is recommended to use Hashtables or PSObjects instead.

It's recommended to switch to either Hashtables or PSObjects, but if you need to use classes then the following should let classes work:
However, if you need to use classes, PowerShell 7.4 introduces the `[NoRunspaceAffinity()]` attribute that makes classes thread-safe by solving this issue.

Here's an example of a class definition with the `[NoRunspaceAffinity()]` attribute:

```powershell
# Class definition with NoRunspaceAffinity attribute
[NoRunspaceAffinity()]
class SafeClass {
static [object] ShowRunspaceId($val) {
return [PSCustomObject]@{
ThreadId = [Threading.Thread]::CurrentThread.ManagedThreadId
RunspaceId = [runspace]::DefaultRunspace.Id
}
}
}
```

If you need to support versions prior to PowerShell 7.4, you can use the following approach:

* Create a module (CreateClassInstanceHelper.psm1) with the content:

Expand Down
93 changes: 93 additions & 0 deletions docs/Tutorials/CORS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@

# CORS

## What is CORS?
Cross-Origin Resource Sharing (CORS) is a security feature implemented by web browsers to restrict web pages from making requests to a different domain than the one that served the web page. This is a critical aspect of web security, helping to prevent malicious sites from accessing sensitive data from another domain.

## CORS Challenges
When developing web applications, you may encounter situations where your web page needs to request resources from a different domain. This can lead to CORS errors if the appropriate headers are not set to allow these cross-origin requests. Common challenges include:
- Handling pre-flight requests.
- Allowing specific methods and headers.
- Managing credentials in cross-origin requests.
- Setting the appropriate origins.

## Addressing CORS Challenges

Pode simplifies handling CORS by providing the `Set-PodeSecurityAccessControl` function, which allows you to define the necessary headers to manage cross-origin requests effectively.

### Key Headers for CORS

1. **Access-Control-Allow-Origin**: Specifies which origins are permitted to access the resource.
2. **Access-Control-Allow-Methods**: Lists the HTTP methods that are allowed when accessing the resource.
3. **Access-Control-Allow-Headers**: Indicates which HTTP headers can be used during the actual request.
4. **Access-Control-Max-Age**: Specifies how long the results of a pre-flight request can be cached.
5. **Access-Control-Allow-Credentials**: Indicates whether credentials are allowed in the request.

### Setting CORS Headers instead

The `Set-PodeSecurityAccessControl` function allows you to set these headers easily. Here’s how you can address common CORS challenges using this function:

1. **Allowing All Origins**
```powershell
Set-PodeSecurityAccessControl -Origin '*'
```
This sets the `Access-Control-Allow-Origin` header to allow requests from any origin.

2. **Specifying Allowed Methods**
```powershell
Set-PodeSecurityAccessControl -Methods 'GET', 'POST', 'OPTIONS'
```
This sets the `Access-Control-Allow-Methods` header to allow only the specified methods.

3. **Specifying Allowed Headers**
```powershell
Set-PodeSecurityAccessControl -Headers 'Content-Type', 'Authorization'
```
This sets the `Access-Control-Allow-Headers` header to allow the specified headers.

4. **Handling Credentials**
```powershell
Set-PodeSecurityAccessControl -Credentials
```
This sets the `Access-Control-Allow-Credentials` header to allow credentials in requests.

5. **Setting Cache Duration for Pre-flight Requests**
```powershell
Set-PodeSecurityAccessControl -Duration 3600
```
This sets the `Access-Control-Max-Age` header to cache the pre-flight request for one hour.

6. **Automatic Header and Method Detection**
```powershell
Set-PodeSecurityAccessControl -AutoHeaders -AutoMethods
```
These parameters automatically populate the list of allowed headers and methods based on your OpenApi definition and defined routes, respectively.

7. **Enabling Global OPTIONS Route**
```powershell
Set-PodeSecurityAccessControl -WithOptions
```
This creates a global OPTIONS route to handle pre-flight requests automatically.

8. **Additional Security with Cross-Domain XHR Requests**
```powershell
Set-PodeSecurityAccessControl -CrossDomainXhrRequests
```
This adds the 'x-requested-with' header to the list of allowed headers, enhancing security.

### Example Configuration

Here is an example of configuring CORS settings in Pode using `Set-PodeSecurityAccessControl`:

```powershell
Set-PodeSecurityAccessControl -Origin 'https://example.com' -Methods 'GET', 'POST' -Headers 'Content-Type', 'Authorization' -Duration 7200 -Credentials -WithOptions -AutoHeaders -AutoMethods -CrossDomainXhrRequests
```

This example sets up CORS to allow requests from `https://example.com`, allows `GET` and `POST` methods, permits `Content-Type` and `Authorization` headers, enables credentials, caches pre-flight requests for two hours, automatically detects headers and methods, and allows cross-domain XHR requests.

### More Information on CORS

For more information on CORS, you can refer to the following resources:
- [Fetch Living Standard](https://fetch.spec.whatwg.org/)
- [CORS in ASP.NET Core](https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-7.0#credentials-in-cross-origin-requests)
- [MDN Web Docs on CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
36 changes: 19 additions & 17 deletions docs/Tutorials/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,20 +68,22 @@ A "path" like `Server.Ssl.Protocols` looks like the below in the file:
}
```

| Path | Description | Docs |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ |
| Server.Ssl.Protocols | Indicates the SSL Protocols that should be used | [link](../Certificates) |
| Server.Request | Defines request timeout and maximum body size | [link](../RequestLimits) |
| Server.AutoImport | Defines the AutoImport scoping rules for Modules, SnapIns and Functions | [link](../Scoping) |
| Server.Logging | Defines extra configuration for Logging, like masking sensitive data | [link](../Logging/Overview) |
| Server.Root | Overrides root path of the server | [link](../Misc/ServerRoot) |
| Server.Restart | Defines configuration for automatically restarting the server | [link](../Restarting/Types/AutoRestarting) |
| Server.FileMonitor | Defines configuration for restarting the server based on file updates | [link](../Restarting/Types/FileMonitoring) |
| Web.OpenApi.DefaultDefinitionTag | Define the primary tag name for OpenAPI ( `default` is the default) | [link](../OpenAPI/OpenAPI) |
| Web.OpenApi.UsePodeYamlInternal | Force the use of the internal YAML converter even if `PSYaml` or `PowerShell-yaml` modules are available (`False` is the default) | |
| Web.Static.ValidateLast | Changes the way routes are processed. | [link](../Routes/Utilities/StaticContent) |
| Web.TransferEncoding | Sets the Request TransferEncoding | [link](../Compression/Requests) |
| Web.Compression | Sets any compression to use on the Response | [link](../Compression/Responses) |
| Web.ContentType | Define expected Content Types for certain Routes | [link](../Routes/Utilities/ContentTypes) |
| Web.ErrorPages | Defines configuration for custom error pages | [link](../Routes/Utilities/ErrorPages) |
| Web.Static | Defines configuration for static content, such as caching | [link](../Routes/Utilities/StaticContent) |
| Path | Description | Docs |
| -------------------------------- | --------------------------------------------------------------------------- | ----------------------------------------------------------------------- |
| Server.Ssl.Protocols | Indicates the SSL Protocols that should be used | [link](../Certificates) |
| Server.Request | Defines request timeout and maximum body size | [link](../RequestLimits) |
| Server.AutoImport | Defines the AutoImport scoping rules for Modules, SnapIns and Functions | [link](../Scoping) |
| Server.Logging | Defines extra configuration for Logging, like masking sensitive data | [link](../Logging/Overview) |
| Server.Root | Overrides root path of the server | [link](../Misc/ServerRoot) |
| Server.Restart | Defines configuration for automatically restarting the server | [link](../Restarting/Types/AutoRestarting) |
| Server.FileMonitor | Defines configuration for restarting the server based on file updates | [link](../Restarting/Types/FileMonitoring) |
| Server.ReceiveTimeout | Define the amount of time a Receive method call will block waiting for data | [link](../Endpoints/Basic/StaticContent/#server-timeout) |
| Server.DefaultFolders | Set the Default Folders paths | [link](../Routes/Utilities/StaticContent/#changing-the-default-folders) |
| Web.OpenApi.DefaultDefinitionTag | Define the primary tag name for OpenAPI ( `default` is the default) | [link](../OpenAPI/Overview) |
| Web.OpenApi.UsePodeYamlInternal | Force the use of the internal YAML converter (`False` is the default) | |
| Web.Static.ValidateLast | Changes the way routes are processed. | [link](../Routes/Utilities/StaticContent) |
| Web.TransferEncoding | Sets the Request TransferEncoding | [link](../Compression/Requests) |
| Web.Compression | Sets any compression to use on the Response | [link](../Compression/Responses) |
| Web.ContentType | Define expected Content Types for certain Routes | [link](../Routes/Utilities/ContentTypes) |
| Web.ErrorPages | Defines configuration for custom error pages | [link](../Routes/Utilities/ErrorPages) |
| Web.Static | Defines configuration for static content, such as caching | [link](../Routes/Utilities/StaticContent) |
14 changes: 14 additions & 0 deletions docs/Tutorials/Endpoints/Basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,17 @@ The following is the structure of the Endpoint object internally, as well as the
| Protocol | string | The protocol of the Endpoint. Such as: HTTP, HTTPS, WS, etc. |
| Type | string | The type of the Endpoint. Such as: HTTP, WS, SMTP, TCP |
| Certificate | hashtable | Details about the certificate that will be used for SSL Endpoints |

## Server timeout

The timeout is configurable using the `ReceiveTimeout` property in the `server.psd1` configuration file, the amount of time is in milliseconds. The meaning is that the server will wait for data to be received before timing out. This is useful for controlling how long the server should wait during data reception operations, enhancing the performance and responsiveness.

To set this property, include it in `server.psd1` configuration file as shown below:

```powershell
@{
Server = @{
ReceiveTimeout = 5000 # Timeout in milliseconds
}
}
```
Loading

0 comments on commit 69790e7

Please sign in to comment.