4

For a .well-known path, I want to return a static JSON file/string.

With nginx, this seems to be possible without creating that file by specifying the content in the configuration file:

location /.well-known/foo {
    return 200 '{"foo": "bar"}';
    default_type application/json;
    add_header Access-Control-Allow-Origin *;
}

Is something similar possible with apache? This is what I have so far:

<Location "/.well-known/foo">
        # return '{"foo": "bar"}'
        ForceType application/json
        Header set Access-Control-Allow-Origin *
</Location>
  • 4
    The purpose of the web server configs isn't code-golf. Create the JSON file and reference it so that it only gets served when requested instead taking up Apache memory at all times. What if you have multiple servers and need to keep that JSON synced between them all? I think the list of what-ifs could go on for a while so let Apache do what it does best, serve files. – MonkeyZeus Apr 30 '21 at 17:39
  • I would argue that the `.well-known`s are part of the server config, so they _do_ fit there. Also, it's 65 bytes. I hope it doesn't take (much) more than 65 bytes of memory to store it, and I'm willing to permanently block 65 bytes of memory for this. And I won't do what-ifs, because I have exactly one server and I seriously doubt that this will change in the near future. So yes, you might be right in general, but in my case, it doesn't really matter. I just thought the nginx config looked nice and hoped I could do the same thing with apache. – anonymus1994.1 May 01 '21 at 21:45

3 Answers3

6

Yes it is kinda possible (in Apache 2.4).

Just add the following directives:

ErrorDocument 200 "{\"foo\": \"bar\"}"
RewriteEngine On
RewriteRule "^/.well-known/foo$" - [R=200,L]

Unfortunately it is (to my knowledge) impossible to set the Content-Type and add custom headers.

Beware that ErrorDocument with 2xx and 3xx is undocumented and might change.

João Alves
  • 511
  • 2
  • 6
  • Creative solution (+1). You can, however, set the `Content-Type` (and other headers) using a conditional `Header` directive based on an env var set by the `RewriteRule` directive. I've expanded on this in [my answer](https://serverfault.com/a/1062092/49157). – MrWhite Apr 30 '21 at 00:13
  • Very creative, I like it :) These two headers are necessary, so this does not completely answer my question, though. – anonymus1994.1 Apr 30 '21 at 00:25
6

Further to @João Alves creative answer you can set the appropriate Content-Type and other custom headers by setting an environment variable on the RewriteRule and using the Header directive to set these headers conditionally based on this env var.

For example:

ErrorDocument 200 '{"foo": "baz"}'

RewriteEngine On

# Trigger the 200 response AND set an environment variable "JSON"
RewriteRule ^/\.well-known/foo$ - [R=200,E=JSON:1,L]

# Set headers if "JSON" env var is set
Header always set Access-Control-Allow-Origin * env=JSON
Header always set Content-Type application/json env=JSON

Note that the always condition on the Header directive is necessary in this case.

However, the above solution only permits a single response (ie. ErrorDocument 200) if you should have other URLs that require a different response. If you declare another ErrorDocument 200 later, it will override the earlier definition, regardless of the ordering of the directives.

You could instead "scope" the ErrorDocument and associated directives by URL-path, using a <Location> block. This also avoids the need for mod_rewrite and the additional env var. For example:

<Location /.well-known/foo>
    ErrorDocument 200 '{"foo": "bar"}'
    Redirect 200 /
    Header always set Content-Type application/json
    Header always set Access-Control-Allow-Origin *
</Location>

(Since this request does not map to a static file, ForceType will have no effect here.)

MrWhite
  • 11,643
  • 4
  • 25
  • 40
  • Thanks for the improvement of @João Alves' answer and correction of my config. This solution is not quite what I had in mind (it's kinda hacky), but it works for my case, so I will accept it if there is no better one. – anonymus1994.1 Apr 30 '21 at 00:34
1

Instead of inserting the content directly in an Apache directive, you can put the content in a file and use an Alias:

Alias /.well-known/foo /path/to/content.json
<Location "/.well-known/foo">
    ForceType application/json
    Header set Access-Control-Allow-Origin *
</Location>

where content.json is a file that includes your content, {"foo": "bar"}.

Andrew Schulman
  • 8,561
  • 21
  • 31
  • 47
  • 1
    Thanks for the answer, but this doesn't really help me. I _can_ create the file, I just don't want to; it seems cleaner in the config file. – anonymus1994.1 Apr 29 '21 at 17:56
  • 3
    It is certainly *not* cleaner having it in the config file. What if you want to change the json content? Edit the config file and reload apache(and hope you don't add a typo the prevents reloading)? And how do you handle If-modified and E-Tag in such a case? – Hagen von Eitzen Apr 30 '21 at 20:37
  • It is much cleaner to keep the served file outside the configuration. Because nginx does stupid things, and make them look like nice and easy, it doesn't mean that we should have an exact solution in apache too. – dashohoxha Jul 01 '22 at 16:06