Gouger

User guide · v0.9.4

Using Gouger

Gouger sits between your browser and the web, records every request and response, and reads them for you: problems are marked on the request where they happen, with a plain explanation and a hint for the fix. This guide walks through the window and then lists every check and the failure it is there to catch.

Getting started

Capture live traffic

  1. Start Gouger. It opens with its proxy already listening, by default on 127.0.0.1:8080 (the green chip in the toolbar).
  2. Click the computer button in the toolbar (or File → Route this computer through Gouger). Gouger installs its own certificate so it can read HTTPS traffic, and points the system proxy at itself. Windows asks you once to confirm the certificate.
  3. Reproduce the problem in the browser. Requests appear in the list as they happen. A browser that was already open may need a restart before it trusts the new certificate.
  4. Click the computer button again when you are done, or just close Gouger: the system proxy goes back to what it was.

On Windows, routing changes the current user's proxy setting (what Edge, Chrome and most apps follow) and certificate store. On Linux it changes the GNOME proxy settings and the certificate databases of Chrome and Firefox; that needs certutil (package libnss3-tools).

To capture only one browser or app, leave the system alone and set that program's proxy to the address on the green chip by hand. To read its HTTPS traffic it must trust Gouger's certificate: the download button at the right of the toolbar saves the certificate file so you can install it where you need it.

If an app refuses Gouger's certificate (some pin their own), the status bar says so. Add its host to the passthrough list in Settings: Gouger then lets that host's traffic through untouched instead of reading it.

Analyze a HAR file

Browsers can save what their developer tools recorded as a HAR file. Open one with File → Import HAR and Gouger runs the same checks as on live traffic, with no proxy or certificate involved. Note that browsers leave cookies out of exported HAR files, so the cookie checks have less to work with; Gouger tells you when that happens.

The window

The Gouger window: toolbar at the top, the request list on the left, the selected request's headers, timing and a slow-response diagnosis on the right, and a status bar along the bottom.
  • Toolbar (top): capture on and off, clear, replay, compose, breakpoints, the filter box, the proxy address, routing and the certificate.
  • Left pane: three tabs. Flows is the request list, Diagnostics lists every problem found, Hosts lists the servers involved.
  • Right pane: the inspector for the selected request: headers, body, query parameters, the raw message and its issues.
  • Status bar (bottom): counts of requests, errors and warnings, sessions and hosts, and messages from the last action.

The divider between the panes can be dragged. The window follows the system's light or dark appearance unless you pick one in Settings.

Toolbar

The toolbar: Capturing button, four round buttons, the filter box, the proxy address chip and a download button.
Capturing / PausedTurns recording on and off. While paused, traffic still flows through Gouger but is not added to the list, so you can skip the parts of a session you do not need.
Clear (bin)Removes every request from the list.
Replay (circular arrow)Sends the selected request again. See Replay.
Compose (pencil)Writes a new request from scratch.
Breakpoints (pause)Opens the breakpoint list. See Breakpoints.
Filter boxShows only the requests that match. See Filtering.
Proxy chipThe address Gouger listens on, green while it is running. Point a browser or app here to capture it.
ComputerRoutes the whole computer through Gouger, and back. Highlighted while routing is on. Shown where Gouger can change the system proxy (Windows, GNOME on Linux).
DownloadSaves Gouger's certificate to a folder of your choice, for browsers, apps or devices you set up by hand.

Request list

The Flows tab lists every request in the order it happened. Each row shows:

!A dot in the colour of the worst issue on the request: red for an error, amber for a warning, blue for information. A hollow dot means no issues.
VERBThe request method (GET, POST…), WS for a WebSocket.
STThe response status, or a dash when no response came back at all.
RESOURCEThe host, dimmed, then the path. Long paths are shortened in the middle.
TIMEHow long the request took, from sending it to the last byte of the response.

Click a row, or use ↑ ↓, to show the request in the inspector. Delete removes the selected request. Requests you sent with Replay or Compose appear in the list like any other, and the inspector says which request they replay.

Sorting

Click a column title to sort by it; the title shows an arrow. Click again to reverse the order, a third time to go back to capture order. The first click sorts the way you most likely want: worst issues first for !, slowest first for TIME, A to Z for the others. Sorting by RESOURCE sorts by host, then path.

Group by session

Tick group by session to arrange requests by the browser session they belong to. Each session starts with a header row (its main host, how many other hosts it touched and how many requests it has); click the header to fold or unfold it.

When a session involves a single sign-on login, its last rows retrace the login step by step: the first visit without a session, the trip to the login server, the return with a ticket, and the service answering. The step where it broke, a service sending the user back to the login server, is in red.

The request list sorted by time, slowest first: a 30-second request at the top.
Sorted by TIME, slowest first.
The request list grouped by session, followed by the session's login steps; two steps where the service sent the user back to the login server are in red.
Grouped by session, with the login steps underneath.

Filtering

Type in the filter box to show only the requests that match. A filter is a list of words separated by spaces; a request must match every word. Upper and lower case do not matter.

bracketAny word without a prefix matches the full address (host, path and query).
host:exampleThe host contains the text. * is allowed and ignored, so host:*.example.com works too.
host:=api.example.comThe host is exactly this one.
status:404The response status is this one.
status:>=400Compare the status: >=, >, <=, <. status:0 finds requests that got no response at all.
method:postThe request method is this one.
ct:jsonThe response content type contains the text.
ctx:engineeringThe security context the request carries (role, organization or collaborative space) contains the text.
-wordA minus in front turns any word around: -host:=cdn.example.com hides that host, -ct:image hides images.

For example, status:>=400 -host:=cdn.example.com shows the failures, except those of the CDN. The filter applies to the request list, to the session grouping and to "Delete the flows shown". Exports can be limited to it. The Hosts tab writes host filters for you.

The filter status:>=400 shows four failed requests; the selected one was refused for its security context.
The filter status:>=400: four requests left, one of them refused for its security context.

Diagnostics tab

The Diagnostics tab: one row per kind of issue, errors first, each with a count and a check box.

Every kind of problem found in the capture, one row each, errors first and then by how often it happened. The colour gives the severity:

  • Error something broke: a failed request, a refusal, a loop.
  • Warning degraded, suspicious or slow; often the cause of an error elsewhere.
  • Info expected behaviour worth knowing about, so it is not mistaken for a failure.

Click a row to jump to the request it is about. For problems that span a whole session, such as a login loop, Gouger switches to the session view and marks the requests involved in red.

Untick the box to mute that kind of issue: it disappears from the request dots, the inspector and the status bar counts, but stays listed here so you can bring it back.

Each check is explained in the checks reference.

Hosts tab

The Hosts tab: four hosts with their request counts; one shows 5 failed, one is hidden and dimmed.

Every server the capture talked to, busiest first, whatever the filter shows. Each row has a dot for the worst issue on that host, the number of failed requests (no response, or a status of 400 and above) and the number of requests.

Click a host to show only its traffic; click it again to show everything. Click the eye at the end of a row to hide that host instead, for example a CDN or analytics server that only adds noise; click it again to bring it back. Both simply edit the filter (host:= and -host:=), so the filter box always says what you are looking at.

The host count at the right of the status bar opens this tab.

Inspector

The right pane shows the selected request. Its top line repeats the method, the address, the status and the time. You can select any text in the inspector with the mouse and copy it with Ctrl+C or the right-click menu.

Headers

The request headers, the response line (status, content type, size, time) and the response headers. A header that carries the security context is marked CONTEXT. Below them, Timing splits the request's time into its phases:

  • blocked, dns, connect, tls, send: getting the request to the server. Long here means the network or the connection setup.
  • wait (TTFB): from the request being sent to the first byte of the answer, which is the time the server spent working. A long amber bar points at the server, not the network.
  • receive: downloading the answer. Long here means a large response or a slow link.

The issues of the request follow, in full.

The Headers tab: request headers with the security context marked, the response line, a timing bar almost entirely taken by the server's wait, and a slow-response warning.
A slow call: nearly all of its 4.9 seconds is the server's wait.

Body

The request and response bodies. JSON is laid out with indentation, images are shown as images, and anything else as text or, for binary content, as a hex dump. Tick Hex to see the exact bytes of any body. Very large bodies show their first 64 KB.

Query

The address's query parameters as a table, decoded, one per row.

Raw

The request and response as they would look on the wire: request line, headers, blank line, body.

Issues

The problems found on this request, each with what was seen and a hint for the fix. The tab title counts them.

The Body tab showing an indented JSON response.
Body: JSON, indented.
The Issues tab with two issues: access denied for the security context, and a missing anti-forgery token.
Issues: a refused call, and the likely reason.
The Query tab: the request's query parameters in a table.
Query parameters.
The Raw tab: the request and response as text.
The raw request and response.

Status bar

The status bar: 25 flows, the proxy address, 931 B, 9 errors, 18 warnings, 1 session, 4 hosts.

From the left: the number of requests, the proxy address, the total size of the request and response bodies, and the number of errors and warnings (muted issues not counted). On the right, the number of sessions and hosts; click it to open the Hosts tab. Messages from your last action, such as where a file was saved, appear here too.

Replay, compose, breakpoints

Replay and compose

Replay opens the selected request in an editor: change the method, address, headers or body, then Send. Compose opens the same editor empty. The request goes out through Gouger, so its answer is captured and checked like any other; the inspector notes which request it replays. Use it to confirm a fix (add the missing header, correct the address) without going through the whole application again.

Breakpoints

A breakpoint holds a request on its way to the server, or a response on its way back, so you can change its headers before letting it continue. Open the list with the pause button. A breakpoint matches on a host (exactly), a path (anything starting with it) and a method; leave a field empty to match anything. Untick a breakpoint to keep it without it firing.

When one fires, a window shows the held message with its headers ready to edit. Continue sends it on, edited; closing the window sends it on unchanged. The browser waits meanwhile, so do not leave it held for too long.

The replay editor: method, address, headers and body, with Cancel and Send.
Replay: edit, then send.
The breakpoint list: a request breakpoint on POST calls to one host's /resources path, and a response breakpoint on another host.
Breakpoints: empty fields match anything.

Save, export, share

Save sessionYour own working copy: every request with its issues, nothing removed, reopened exactly with Open session. Do not send it to anyone: it contains your cookies and credentials.
Export HARA standard HAR file that browsers and other tools can open, for sharing.
Export reportThe Gouger Report: the issues found, grouped and explained, with the login steps of each session, for whoever has to fix the problem, such as your IT team or the application's vendor. HTML opens in any browser; Markdown pastes into most ticket systems.
Copy as cURLOne request as a command line, for someone to reproduce it.
Export report options: HTML or Markdown, redact, and only the flows matching the filter.

Both exports ask two things first. Redact replaces cookie values, passwords, tokens, login tickets, user names and e-mail addresses with placeholders. The same secret always becomes the same placeholder, so the report still shows that a session cookie changed or that a ticket was used twice. Redaction is a strong default, not a guarantee: personal data under names Gouger does not recognize can get through, so look before you send.

Only the flows matching the filter limits the export to what the list shows.

Settings

The Settings window.

Checks reference

What each check is there to catch, and what you would notice in the application when it fires. The code is how the check appears in the Diagnostics tab and in the inspector.

Login and single sign-on

For applications that sign users in through a central CAS login server: a service sends the browser to the login server, which sends it back with a one-time ticket the service checks.

cas.redirect-loopError

Login loop on a service

The browser keeps going to the login server and back for one service and never gets in. Users see the page reload endlessly, or the browser stops with "too many redirects". Gouger lists the likely causes it found evidence for, such as a rejected ticket or a session cookie the service never set.

cas.ticket-validation-failedError

Login ticket rejected

The user signed in and came back to the service with a ticket, but the service sent them straight back to the login server: it did not accept the ticket. Usual causes are a service address that differs from the one the ticket was issued for, a ticket that expired or was already used, or an expired login. The check happens between the servers, out of the browser's sight, so Gouger infers it from what follows.

cas.login-bounceWarning

Request sent back to the login page

A page or service call was answered with a redirect to the login server: the service did not recognize the user's session. Users get logged out, or parts of a page fail to load. Typical causes: the session cookie is not sent to this host (its domain or path), the session expired, or the load balancer sent the user to a server that does not know the session.

cas.service-url-mismatchWarning

Service address differs from the one requested

The address the service gives the login server to come back to is not exactly the address the user asked for: a different scheme, host, port or path, a trailing slash, or only upper and lower case. The ticket is issued for one address and checked against the other, so the login fails or loops.

cas.ticket-replayWarning

Login ticket used twice

A one-time login ticket was presented a second time; the second use always fails. It happens when the user goes back or reloads the ticket address, when a retry repeats the request, or when a cache between the browser and the server replays it.

cas.no-tgtWarning

No single sign-on cookie

The user went through the login server, but its single sign-on cookie never appears. Without it, every service asks the user to sign in again: single sign-on does not work. Typically the browser rejected the cookie because of its domain, path or security attributes.

cas.gateway-bounceInfo

Silent login check

A service asked the login server whether the user is already signed in, without showing a login page. This is normal; it is listed so the extra redirect is not mistaken for a failure.

Security context

For applications whose web-service calls carry a security context: the role, organization and collaborative space the user works under.

ctx.deniedError

Access denied for the security context

A call made under a given role, organization and space was refused (401 or 403). The user typically does not hold that role in that space or organization. Gouger shows the refusal, not the server's reason: check the user's roles and the space's membership.

ctx.selection-errorError

Choosing the security context failed

The server rejected the selected context, the context picker failed, or setting the user's preferred context failed. Users cannot pick a space, or the application starts without the context they expect.

ctx.missingWarning

Web-service call without a security context

A web-service call carries no security context while the session's other calls do. The server cannot tell under which role and space to authorize it, so it may refuse the call or answer under a default. One feature fails while the rest of the application works.

ctx.malformedWarning

Malformed security context

The security context is present but not in the expected role, organization and space form: a part is missing or extra, the value is cut short, or it contains stray characters. The server cannot resolve it.

ctx.switchWarning

Security context changed during the session

The role, organization or space changed in the middle of a session. That explains "it worked a minute ago": what was opened under the earlier context can stop working. Look at what triggered the switch: the user changing space, a role change, or a fallback to a default.

csrf.missing-tokenWarning

Change without the anti-forgery token

A call that changes data (POST, PUT or DELETE) does not carry the anti-forgery token the session was given. The server rejects such calls: reading works, but saving, locking or deleting fails.

Cookies and sessions

cookie.jar-mismatchWarning

Cookie missing from a request

A cookie the server set earlier, which the browser should have sent back, is missing from a request. The application loses track of the user: random logouts, a cart or form that empties. The browser dropped it: it expired, its domain or path did not fit, or it was cleared.

cookie.domain-mismatchWarning

Cookie set for another domain

A server sets a cookie for a domain that does not include the site that sent it. Browsers silently ignore such cookies, so whatever depends on it, often the session, never works.

cookie.samesite-none-insecureWarning

Cross-site cookie without Secure

A cookie meant to work across sites (SameSite=None) lacks the Secure attribute. Browsers reject it, so single sign-on and embedded applications that rely on it lose the session.

cookie.missing-secureWarning

Cookie without Secure on HTTPS

A cookie set over HTTPS without the Secure attribute may also travel over plain HTTP, where anyone on the network can read it. For a session cookie, that exposes the user's session.

cookie.shadowWarning

Same cookie on two paths

The same cookie name is set for two paths. On pages under both, the browser sends the more specific one, so the application can read an old or wrong value: settings or sessions that do not stick on some pages.

affinity.flipWarning

Session moved to another server

The session cookie changed in mid-session, or one host was answered by several different servers. When a load balancer does not keep a user on the same server, what that server held in memory for the session is lost: sudden logouts, failed uploads, data that seems to come and go.

cookie.har-degradedInfo

No cookies in the capture

The capture has no cookies at all, which is how browsers export HAR files. The cookie checks cannot run on it. To investigate cookies, capture live through Gouger instead.

Redirects

redirect.loopError

Redirect loop

A chain of redirects that never reaches a page. The browser gives up with "too many redirects". Login servers, stale session cookies and HTTP/HTTPS rules that undo each other are the usual suspects.

redirect.single.downgradeWarning

Redirect from HTTPS to HTTP

A secure page sends the browser to an insecure address. Cookies and credentials on the next request travel unencrypted, and browsers may block or warn about it.

redirect.single.internal-hostWarning

Redirect to an internal address

A redirect points to a private network address or internal name that users outside the network cannot reach. Usually a proxy or single sign-on setting that still names the server behind it.

redirect.single.lost-queryWarning

Redirect drops query parameters

A redirect to the same page loses part of the address's query. The application forgets what was asked for: a search, a filter, a deep link.

redirect.single.cached-authWarning

Cacheable redirect carries a one-time credential

A redirect that caches may keep (301, 302) has a ticket or token in its address. A cache between the browser and the server could serve it again, and such addresses end up in browser history and server logs. Login servers commonly hand back tickets this way; it becomes a problem when a cache sits in between (see cas.ticket-replay).

Caching

cache.no-store-staticWarning

Static file that may not be stored

A script, style sheet, font or image is marked never to be stored. It is downloaded in full on every page load: slow pages, especially over long distances.

cache.no-validatorWarning

Cacheable response without a validator

The response may be cached but carries no version tag (ETag or Last-Modified). Once it expires, the browser cannot ask whether it changed and must download it again in full.

cache.200-not-304Warning

Unchanged file downloaded again

The browser asked whether a file it already has had changed, and the server sent the whole file again. Caching is not working for it: wasted bandwidth and slower loads.

cache.conflicting-directivesWarning

Contradictory caching instructions

The response's caching instructions contradict each other, such as "never store" with "keep for an hour", or public with private. Browsers and proxies may cache it differently than intended, sometimes keeping private data where they should not.

Headers and cross-origin calls

header.cors-preflightWarning

Cross-origin call not allowed

The browser asked a server for permission to call it from another site, and the server did not grant it. The browser then blocks the real call: a feature silently does nothing, and the browser's console shows a CORS error.

header.xfh-mismatchWarning

Forwarded address does not match

A proxy in front of the application tells it the request arrived under a different host or scheme than it did. The application then builds wrong links and redirects, such as HTTP instead of HTTPS or an internal host name, and single sign-on addresses stop matching.

header.duplicate-conflictWarning

Same header twice with different values

Two layers, such as the application and a proxy, both set the same header to different values. Which one wins depends on the client, so behaviour varies.

Responses and timing

upstream.failedError

Request failed or server error

No answer came back (connection refused or reset, timeout, a failed secure connection), or the server answered with an error (500 and above). Check that the server and anything in front of it, such as a load balancer or gateway, are up and healthy.

json.malformedError

Broken JSON response

A response that should be JSON cannot be read: it was cut short on the way, or it is an error page sent as JSON. The application shows a generic error or an empty view. It is a warning instead when the body was too large for Gouger to capture in full.

timing.slowWarning

Slow response

The request took longer than the slow threshold (three seconds unless changed in Settings). The inspector's timing shows whether the server's work or the transfer took the time.

websocketInfo

WebSocket connection

The application opened a WebSocket, a long-lived two-way connection. Gouger shows that it was opened but not the messages that go through it.