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

Addition of documentation describing how to debug #1282

Merged
merged 3 commits into from
Apr 7, 2024
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
176 changes: 176 additions & 0 deletions docs/Getting-Started/Debug.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
# Debugging Pode

When using Pode there will often be times when you need to debug aspects of your scripts. Debugging in Pode can be achieved in a couple of ways:

1. Write messages to the console.
2. Use PowerShell's debugger.

## Messages

To output messages from your Routes, Timers, etc. you can either call PowerShell's `Out-Default`, or Pode's [`Out-PodeHost`](../../Functions/Utilities/Out-PodeHost). The latter is just a wrapper around `Out-Default` however, it respects the `-Quiet` switch if supplied to [`Start-PodeServer`](../../Functions/Core/Start-PodeServer) - suppressing the messages when not needed.

For example, the following will output messages and variables from a Route:

```powershell
Start-PodeServer {
Add-PodeEndpoint -Address localhost -Port 8080 -Protocol Http

Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
'Start of / Route' | Out-PodeHost
$processes = Get-Process
"Processes found: $($processes.Length)" | Out-PodeHost
$processes[0] | Out-PodeHost
Write-PodeJsonResponse -Value @{ Process = $processes[0] }
}
}
```

This will output 3 messages to the host window where Pode is running when the Route is invoked, as follows:

```powershell
Invoke-RestMethod -Uri 'http://localhost:8080/'
```

```plain
Start of / Route
Processes found: 393

NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
7 2.45 3.66 3.48 7044 0 AggregatorHost
```

!!! tip
You can leave the `Out-PodeHost` lines in place, and suppress them by passing `-Quiet` to `Start-PodeServer`.

## Debugger

You can breakpoint directly into a running Pode server by using either PowerShell's `Wait-Debugger` or Pode's [`Wait-PodeDebugger`](../../Functions/Core/Wait-PodeDebugger). The latter is just a wrapper around `Wait-Debugger` however, it respects the `-EnableBreakpoints` switch if supplied to [`Start-PodeServer`](../../Functions/Core/Start-PodeServer) - allowing you to suppress the breakpoints when not needed. Regardless of the Wait command chosen, the process to attach to the Pode process is the same.

For example, the following will create a breakpoint for PowerShell's debugger when the Route is invoked:

```powershell
Start-PodeServer -EnableBreakpoints {
Add-PodeEndpoint -Address localhost -Port 8080 -Protocol Http

Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
Wait-PodeDebugger
$processes = Get-Process
Write-PodeJsonResponse -Value @{ Process = $processes[0] }
}
}
```

The steps to attach to the Pode process are as follows:

1. In a PowerShell console, start the above Pode server. You will see the following output, and you'll need the PID that is shown:
```plain
Pode v2.10.0 (PID: 28324)
Listening on the following 1 endpoint(s) [1 thread(s)]:
- http://localhost:8080/
```

2. In a browser or a new PowerShell console, invoke the `[GET] http://localhost:8080` Route to hit the breakpoint.
```powershell
Invoke-RestMethod -Uri 'http://localhost:8080/'
```

3. Open another new PowerShell console, and run the following command to enter the first PowerShell console running Pode - you'll need the PID as well:
```powershell
Enter-PSHostProcess -Id '<PID_HERE>'
```

4. Once you have entered the PowerShell console running Pode, run the below command to attach to the breakpoint:
```powershell
Get-Runspace |
Where-Object { $_.Debugger.InBreakpoint } |
Select-Object -First 1 |
Debug-Runspace -Confirm:$false
```

1. If you used `Wait-PodeDebugger` you'll need to hit the `s` key twice to get to the next actual line.

5. Hit the `h` key to see the debugger commands you can use. In general, you'll be after:
1. `s`: step into the next line, function, script
2. `v`: step over the next line
3. `o`: step out of the current function
4. `d`: detach from the debugger, and let the script complete

6. You'll also be able to query variables as well, such as `$WebEvent` and other variables you might have created.

7. When you are done debugging the current request, hit the `d` key.

8. When you're done with debugging altogether, you can exit the entered process as follows:
```powershell
exit
```

### Toggle Breakpoints

If you're using [`Wait-PodeDebugger`](../../Functions/Core/Wait-PodeDebugger) then you can leave these breakpoint lines in place, and toggle them in non-developer environments by passing `-EnableBreakpoints` to [`Start-PodeServer`](../../Functions/Core/Start-PodeServer). If you don't supply `-EnableBreakpoints`, or you explicitly pass `-EnableBreakpoints:$false`, then this will disable the breakpoints from being set.

You can also toggle breakpoints via the `server.psd1` [configuration file](../../Tutorials/Configuration):
```powershell
@{
Server = @{
Debug = @{
Breakpoints = @{
Enable = $true
}
}
}
}
```

!!! note
The default state is disabled.

### Add-Debugger

You can also use the [Add-Debugger](https://www.powershellgallery.com/packages/Add-Debugger) script from the PowerShell Gallery, allowing you to debug your Pode server within the same console that started Pode - making the debug process smoother, and not requiring multiple PowerShell consoles.

To install `Add-Debugger`, you can do the following:

```powershell
Install-Script -Name Add-Debugger
```

Once installed, you'll be able to use the `Add-Debugger` command within your Routes/etc., alongside `Wait-Debugger`/`Wait-PodeDebugger`.

!!! note
If you're using `-EnableBreakpoints`, then setting this to false will not suppress calls to `Add-Debugger`.

```powershell
Start-PodeServer -EnableBreakpoints {
Add-PodeEndpoint -Address localhost -Port 8080 -Protocol Http

Add-PodeRoute -Method Get -Path '/' -ScriptBlock {
Add-Debugger
Wait-PodeDebugger
$processes = Get-Process
Write-PodeJsonResponse -Value @{ Process = $processes[0] }
}
}
```

The steps to attach to the Pode process are as follows:

1. In a PowerShell console, start the above Pode server.

2. In a browser or a new PowerShell console, invoke the `[GET] http://localhost:8080` Route to hit the breakpoint.
```powershell
Invoke-RestMethod -Uri 'http://localhost:8080/'
```

3. Back in the PowerShell console running Pode, you'll see that it is now attached to the breakpoint for debugging.
1. If you used `Wait-PodeDebugger` you'll need to hit the `s` key twice to get to the next actual line.

4. Hit the `h` key to see the debugger commands you can use. In general, you'll be after:
1. `s`: step into the next line, function, script
2. `v`: step over the next line
3. `o`: step out of the current function
4. `d`: detach from the debugger, and let the script complete

5. You'll also be able to query variables as well, such as `$WebEvent` and other variables you might have created.

6. When you are done debugging the current request, hit the `d` key.
15 changes: 11 additions & 4 deletions docs/Getting-Started/KnownIssues.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Below is a list of reported issues when using Pode and, if possible, how to reso

Reported in issue [#45](https://github.com/Badgerati/Pode/issues/45).

On Windows systems there is a limit on the maximum length of URL segments. It's usually about 260 characters, and anything above this will cause Pode to throw a 400 Bad Request error.
On Windows systems, there is a limit on the maximum length of URL segments. It's usually about 260 characters and anything above this will cause Pode to throw a 400 Bad Request error.

To resolve, you can set the `UrlSegmentMaxLength` registry setting to 0 (for unlimited), or any other value. The below PowerShell will set the value to unlimited:
To resolve this, you can set the `UrlSegmentMaxLength` registry setting to 0 (for unlimited), or any other value. The below PowerShell will set the value to unlimited:

```powershell
New-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Services\HTTP\Parameters' -Name 'UrlSegmentMaxLength' -Value 0 -PropertyType DWord -Force
Expand All @@ -18,15 +18,15 @@ 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 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.

You can find more information about this issue [here on PowerShell](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.

It's recommended to switch to either Hashtables or PSObjects, but if you need to use classes then the following should let classes work:

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

```powershell
$Script:powershell = $null
Expand Down Expand Up @@ -105,3 +105,10 @@ Start-PodeServer {
## Loader Errors / Pode Types

If on importing the module you receive Loader Exceptions, or when starting your server you get an error similar to `[PodeListener] not found`, then you will need to update to .NET 4.7.2.

## Slow Requests

If you are experiencing slow response times on Windows using either `Invoke-WebRequest` or `Invoke-RestMethod`, this could be due to a quirk in how these functions work - whereby they try to send the request using IPv6 first, then try IPv4. To potentially resolve the slowness, you can either:

1. Use the IPv4 address instead of the hostname. For example, using `http://127.0.0.1:8080` instead of `http://localhost:8080`.
2. Enable [Dual Mode](../../Tutorials/Endpoints/Basics#dual-mode) on your [`Add-PodeEndpoint`](../../Functions/Core/Add-PodeEndpoint) so that it listens on both IPv4 and IPv6.
19 changes: 9 additions & 10 deletions docs/Getting-Started/build.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

# Build Pode
# Building Pode

To build and use the code checked out on your machine, follow these steps :
If you have Pode's source code checked out locally on your machine, you can follow these steps to build Pode:

## Windows

Expand Down Expand Up @@ -51,7 +51,7 @@ To build and use the code checked out on your machine, follow these steps :
Invoke-Build Install-Module
```

To uninstall, use :
To uninstall, use:
```powershell
Invoke-Build Remove-Module
```
Expand All @@ -69,13 +69,13 @@ To build and use the code checked out on your machine, follow these steps :

1. Register the Microsoft Repository

#### Centos
#### CentOS
```shell
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo curl -o /etc/yum.repos.d/microsoft.repo https://packages.microsoft.com/config/centos/8/prod.repo
```

#### ReadHat
#### RedHat
```shell
sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc
sudo curl -o /etc/yum.repos.d/microsoft.repo https://packages.microsoft.com/config/rhel/9/prod.repo
Expand Down Expand Up @@ -129,7 +129,7 @@ To build and use the code checked out on your machine, follow these steps :
Invoke-Build Install-Module
```

To uninstall, use :
To uninstall, use:

```powershell
Invoke-Build Remove-Module
Expand All @@ -138,9 +138,9 @@ To build and use the code checked out on your machine, follow these steps :

## MacOS

An easy way to install the required componentS is to use [brew](https://brew.sh/)
An easy way to install the required components is to use [brew](https://brew.sh/):

1. Install dotNet
1. Install dotnet:

```shell
brew install dotnet
Expand Down Expand Up @@ -184,9 +184,8 @@ An easy way to install the required componentS is to use [brew](https://brew.sh/
Invoke-Build Install-Module
```

To uninstall, use :
To uninstall, use:

```powershell
Invoke-Build Remove-Module
```

38 changes: 19 additions & 19 deletions docs/Tutorials/Middleware/Overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

Middleware in Pode allows you to observe and edit the request/response objects for a current [web event](../../WebEvent) - you can alter the response, add custom objects to the [web event](../../WebEvent) for later use, or terminate the response without processing the main Route logic.

Middleware is supported in both a global scope, using [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware), as well as at the Route level using the `-Middleware` parameter on [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware),
Middleware is supported in both a global scope, using [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware), as well as at the Route level using the `-Middleware` parameter on [`Add-PodeRoute`](../../../Functions/Routes/Add-PodeRoute).

Pode itself has some inbuilt Middleware, which is overridable, so you can use your own custom middleware. For example, Pode has inbuilt Middleware for rate limiting, but you can override this with [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware) and the Name `__pode_mw_rate_limit__` (more on the [Access Rules](../Types/AccessRules) and [Rate Limiting](../Types/RateLimiting) page).

## Global Middleware

To setup and use middleware in Pode you use the Middleware function: [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware). This will setup global middleware that will run, in the order created, on every request prior to any Route logic being invoked.
To set up and use middleware in Pode you use the Middleware function: [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware). This will set up global middleware that will run, in the order created, on every request before any Route logic is invoked.

The function takes a ScriptBlock, which has access to the current [web event](../../WebEvent) variable: `$WebEvent`. The event object contains the current `Request` and `Response` objects - you can also add more custom objects to it, as the event is just a `hashtable`.

Expand Down Expand Up @@ -37,7 +37,7 @@ Start-PodeServer {
}
```

Where as the following example is Middleware that will only be run on requests against the `/api` route. Here, we're just going to do something simple, which is to write a message to the console for all `/api` requests:
However, the following example is Middleware that will only be run on requests against the `/api` route. Here, we're just going to do something simple, which is to write a message to the console for all `/api` requests:

```powershell
Start-PodeServer {
Expand All @@ -50,7 +50,7 @@ Start-PodeServer {

## Route Middleware

Custom middleware on a Route is basically the same as above however, you don't use the main Middleware functions and instead insert it straight on the Route. To do this, you can use the `-Middleware` parameter on the [`Add-PodeRoute`](../../../Functions/Routes/Add-PodeRoute) function.
Custom middleware on a Route is the same as above however, you don't use the main Middleware functions and instead insert it straight on the Route. To do this, you can use the `-Middleware` parameter on the [`Add-PodeRoute`](../../../Functions/Routes/Add-PodeRoute) function.

The middleware on a route can either be a single `scriptblock` or an an array of `scriptblocks`. Middleware defined on routes will be run before the route itself, but after any global middleware that may have been configured.

Expand Down Expand Up @@ -86,23 +86,23 @@ Start-PodeServer {

Although you can define your own custom middleware, Pode does have some inbuilt middleware with a predefined run order. This order of running is as follows:

| Order | Middleware | Description |
| ----- | ---------- | ----------- |
| 1 | **Security Headers** | Add any defined security headers onto the response |
| 2 | **Access Rules** | Allowing/Denying IP addresses (if access rules have been defined) |
| 3 | **Rate Limiting** | Limiting access to IP addresses (if rate limiting rules have been defined) |
| 4 | **Static Content** | Static Content, such as images/css/js/html, in the `/public` directory |
| 5 | **Body Parsing** | Parsing request payload as JSON, XML, or other types |
| 6 | **Query String** | Getting any query string parameters currently on the request URL |
| 7 | **Cookie Parsing** | Parse the cookies from the request's header (this only applies to serverless) |
| 8 | **Custom Middleware** | Runs any defined user defined global Middleware in the order it was created |
| 9 | **Route Middleware** | Runs any Route level Middleware for the current Route being processed |
| 10 | **Route** | Then, the route itself is processed |
| 11 | **Endware** | Finally, any Endware configured is run |
| Order | Middleware | Description |
| ----- | --------------------- | ----------------------------------------------------------------------------- |
| 1 | **Security Headers** | Add any defined security headers onto the response |
| 2 | **Access Rules** | Allowing/Denying IP addresses (if access rules have been defined) |
| 3 | **Rate Limiting** | Limiting access to IP addresses (if rate limiting rules have been defined) |
| 4 | **Static Content** | Static Content, such as images/css/js/html, in the `/public` directory |
| 5 | **Body Parsing** | Parsing request payload as JSON, XML, or other types |
| 6 | **Query String** | Getting any query string parameters currently on the request URL |
| 7 | **Cookie Parsing** | Parse the cookies from the request's header (this only applies to serverless) |
| 8 | **Custom Middleware** | Runs any defined user defined global Middleware in the order it was created |
| 9 | **Route Middleware** | Runs any Route level Middleware for the current Route being processed |
| 10 | **Route** | Then, the route itself is processed |
| 11 | **Endware** | Finally, any Endware configured is run |

## Overriding Inbuilt

Pode has inbuilt Middleware as defined in the order of running above. Sometimes you probably don't want to use the inbuilt rate limiting, and use a custom rate limiting library that utilises REDIS instead. Each of the inbuilt Middleware have a defined name, that you can pass to the [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware) function via the `-Name` parameter:
Pode has inbuilt Middleware as defined in the order of running above. Sometimes you probably don't want to use the inbuilt rate-limiting, and use a custom rate-limiting library that utilises REDIS instead. Each of the inbuilt Middleware has a defined name, that you can pass to the [`Add-PodeMiddleware`](../../../Functions/Middleware/Add-PodeMiddleware) function via the `-Name` parameter:

* Access Control - `__pode_mw_access__`
* Rate Limiting - `__pode_mw_rate_limit__`
Expand All @@ -112,7 +112,7 @@ Pode has inbuilt Middleware as defined in the order of running above. Sometimes
* Cookie Parsing - `__pode_mw_cookie_parsing__`
* Security Headers - `__pode_mw_security__`

The following example uses rate limiting, and defines Middleware that will override the inbuilt rate limiting logic:
The following example uses rate limiting, and defines Middleware that will override the inbuilt rate-limiting logic:

```powershell
Start-PodeServer {
Expand Down
Loading
Loading