WebHostUrl not working if path is /metadata/

I am running a self hosted SS installed on http://mybox:123

In the config I set the WebHostUrl to https://mydomain.com/api

I have a transparent proxy forwarding the requests, so far so good. All my services and the metadata page work correctly except if I enter a trailing slash when trying to access the metadata page, ie. https://mydomain.com/api/metadata/. The returned URL from ServiceStack is then http://mydomain.com:123 which obviously does not work.

Is there anything else I need to do / some way to better debug the problem?

Thanks

Nic

The /metadata route is a page (i.e. not a directory with an index page) so /api/metadata is the correct route but there should still be a fallback redirect back to the /metadata page which I’ve just double-checked that this works in a self HttpListener host configured at /api.

The Debugging page has some useful info to help debugging, e.g. you should set DebugMode = true and then you can call ?debug=requestinfo to view info about the Request ServiceStack sees as well as what paths they resolve to.

The Request Logger lets you record the Requests ServiceStack receives so you can see what Request the transparent proxy is sending. If you’re running a reverse proxy you generally want it to set proxy HTTP Headers, e.g. this is what you’d typically set in an nginx reverse proxy:

    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;

Fiddler or Web Inspector is useful to view the raw HTTP Request and the Redirect.

So the logging doesn’t really help much. It looks as if requests for /metadata are not logged by the default logging and I can’t get the ?debug=requestinfo because my browser has been redirected to an invalid URL.

Using fiddler I am seeing:

Request:
GET https://mydomain.com:4430/999023/metadata/ HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, /
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299
Accept-Encoding: gzip, deflate, br
Host: mydomain.com:4430
Connection: Keep-Alive

Response
HTTP/1.1 302 Found
Location: http://mydomain.com:36380/metadata
Vary: Accept
Server: Microsoft-HTTPAPI/2.0
X-Powered-By: ServiceStack/5.10 NET45 Win32NT/.NET
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type
Date: Thu, 01 Nov 2018 16:34:12 GMT
Content-Length: 0

Not sure where to go next so any suggestions welcome. I can download the debug symbols but I’m not sure what or where I should look.

TIA

Nic

Yeah only Service Requests are logged by default, you can expand the request logging with:

Plugins.Add(new RequestLogsFeature { LimitToServiceRequests = false } );

Not sure if this is a proxy detail or not, but if your Service receives this request:

GET https://mydomain.com:4430/999023/metadata/ HTTP/1.1

Then your self-host would need to be configured to use 999023 not api.

To help debugging you can register a PreRequestFilter and set a break point to inspect the req

PreRequestFilters.Add((req, res) => {
    if (req.PathInfo.StartsWith("...")) {
        "HERE".Print();
    }
});

You can also move the RequestInfo Handler before the Redirect Handler so it doesn’t get redirected with:

RawHttpHandlers.Insert(0, ReturnRequestInfoHandler);

Thanks - I’m still not seeing any redirect information, either logged or hitting a breakpoint in the PreRequestFilters. I’ve pulled the proxy logs and the invalid redirect does appear to come from SS.

Sorry about the confusion, its because I have to jump to a different system to get the error, so let me try again, being more careful to get the details only from the test system:

I’m running a self hosted SS at: http://myserver:36380

I’m setting the WebHostURL to https://mydomain.com:4430/api/

The request being sent to SS is: https://mydomain.com:4430/api/metadata/

The response from SS is a 302 with a location of http://mydomain.com:36380/metadata

Can you provide the raw HTTP Request/Response Headers of the redirect response from ServiceStack.

Did you try adding the info handler to the first RawHttpHandlers?

RawHttpHandlers.Insert(0, ReturnRequestInfoHandler);

It should be returning the ?debug=requestinfo request info before the redirect.

Another thing you can do is override ResolveAbsoluteUrl() in your AppHost and put a breakpoint to see the URL resolved for the Request:

public override string ResolveAbsoluteUrl(string virtualPath, IRequest httpReq)
{
    var resolvedUrl = base.ResolveAbsoluteUrl(virtualPath, httpReq);
    return resolvedUrl;
}

Yes I added the RawHttpHandlers but no requests logged. I’m not sure what you mean by ?debug=requestinfo.

The request / response captured by the Proxy were:

GET /api/metadata/ HTTP/1.1
Accept: text/html, application/xhtml+xml, image/jxr, /
Accept-Language: en-GB
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299
Accept-Encoding: gzip,deflate
Host: mydomain.com:4430
Connection: Keep-Alive

HTTP/1.1 302 Found
Transfer-Encoding: chunked
Location: http://mydomain.com:36380/metadata
Vary: Accept
Server: Microsoft-HTTPAPI/2.0
X-Powered-By: ServiceStack/5.41 Net45/Windows
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS
Access-Control-Allow-Headers: Content-Type
Date: Fri, 02 Nov 2018 11:16:13 GMT

I’ll give the ResolveAbsoluteURL a go and see what else I can find.

Thanks again

Nic

Best I can tell ResolveAbsoluteURL isn’t being called.

Is there anything I can do in SS to dump each and every request / response? Its almost impossible for me to intercept the traffic between the proxy and SS

Thanks again

Nic

The ?debug=requestinfo page lets you view the Request ServiceStack receives, e.g. what does the URL below return:

I’m hoping to see the raw HTTP Headers of the Request that ServiceStack receives as it’s going to be a lot more informative than what the proxy returns.

The Request Logger is the best tool for this, primarily for Service requests but can be expanded to include other requests with LimitToServiceRequests = false.

Whereas ?debug=requestinfo lets you see info on the current request.

You can intercept every ServiceStack request by registering a RawHttpHandlers as it’s the first filter every ServiceStack request uses.

So you can debug every Request ServiceStack receives by putting a breakpoint in:

RawHttpHandlers.Add(new CustomActionHandler(
    (httpReq, httpRes) => {
        "Breakpoint here".Print();
    });

If it’s not hitting the breakpoint then you have something wrong with your debugging environment (e.g. Release mode) as every ServiceStack request goes through RawHttpHandlers.

OK so this is what the /metadata shows:

{"Usage":"append '?debug=requestinfo' to any querystring. Optional params: virtualPathCount","Host":"_v5.41_Web API","HostType":"SelfHost (AppSelfHostBase)","StartedAt":"2018-11-02 13:56:55","Date":"2018-11-02 14:21:00","ServiceName":"Web API","UserHostAddress":"10.200.19.25","HttpMethod":"GET","PathInfo":"/metadata","OriginalPathInfo":"/metadata","StripApplicationVirtualPath":false,"GetPathUrl":"http://mydomain.com:36380/metadata", "AbsoluteUri":"http://mydomain.com:36380/metadata?debug=requestinfo","WebHostUrl":"https://mydomain.com:4430/api/","ApplicationBaseUrl":"https://mydomain.com:4430/api/","ResolveAbsoluteUrl":"https://mydomain.com:4430/api/resolve","RootDirectoryPath":"C:\\WebAPIbin","CurrentDirectory":"C:\\Windows\\system32","RawUrl":"/metadata?debug=requestinfo","Status":0,"ContentLength":0, "Headers":{"Connection":"Keep-Alive","Accept":"text/html, application/xhtml+xml, image/jxr, */*","Accept-Encoding":"gzip,deflate","Accept-Language":"en-GB","Host":"mydomain.com:4430","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 Edge/16.16299"},"QueryString":{"debug":"requestinfo"}, "FormData":{},"AcceptTypes":["text/html","application/xhtml+xml","image/jxr","*/*"],"OperationName":"metadata","ResponseContentType":"text/html","RequestAttributes":"LocalSubnet, InSecure, HttpGet","Ipv4Addresses":"10.200.19.244/255.255.255.0, 127.0.0.1/255.0.0.0","Ipv6Addresses":"fe80::94b8:6040:a453:7b9e, ::1, fe80::5efe:10.200.19.244","DebugString":"", "PluginsLoaded":["HtmlFormat","CsvFormat","PredefinedRoutesFeature","MetadataFeature","NativeTypesFeature","HttpCacheFeature","RequestInfoFeature","SpanFormats","OpenApiFeature","CorsFeature","PostmanFeature","SoapFormat","RequestLogsFeature"],"StartUpErrors":[],"AsyncErrors":[],"Stats":{"RawHttpHandlers":"4","PreRequestFilters":"1","RequestBinders":"0", "GlobalRequestFilters":"1","GlobalRequestFiltersAsync":"0","GlobalResponseFilters":"1","GlobalResponseFiltersAsync":"1","CatchAllHandlers":"4","Plugins":"13","ViewEngines":"0","RequestTypes":"220","ResponseTypes":"184","ServiceTypes":"80","RestPaths":"220","ContentTypes":"8","EnableFeatures":"All","VirtualPathProvider": "[FileSystemVirtualFiles: C:\\WebAPIbin], [ResourceVirtualFiles: WebServices], [ResourceVirtualFiles: ServiceStack], [ResourceVirtualFiles: ServiceStack.Api.OpenApi]"},"VirtualPathProviderFiles":[]}

Looks like the request ServiceStack received was:

If you want to host it on /api it should be receiving:

So confused now :smile:

Those are the http headers as you requested from /metadata, ie the request that works and returns the metadata page. I believe that would be the correct AbsoluteUri as the actual service is on http://myserver:36380.

The headers where the request does not work (/metadata/) are exactly the same but just have the last /, so for example “AbsoluteUri”:“http://mydomain.com:36380/metadata/?debug=requestinfo” . This is what returns the 302 if I leave off the debug=requestinfo.

TIA

Nic

Your AppHost is misconfigured is it’s hosted at /api but the request doesn’t include /api prefix when requesting /metadata.

Why event host it at /api? just leave it at / and have the proxy redirect to http://mydomain.com:36380/.