Chapter 7. Serving Files
HTTPD answers a request that no route claims by sending a file from its document root. This chapter shows where those files are, how they get there, and what HTTPD makes of a request for one: the content type, the directory rules, the path rules and the methods it accepts. The sessions use curl as in Chapter 3, “A First Request”. The Reference describes the same rules as a list. It is the chapter “HTTP Behaviour and Limits” in the HTTPD Reference, and the keywords are in “The HTTPPRM Keywords”.
Where the Files Are
HTTPD does not read files from MVS data sets. It reads them from a UFS file system, which UFSD provides. The Parmlib keyword DOCROOT names the directory in that file system where the files are. The default is /www. HTTPD puts the value in front of the path of the request: a request for /hello.txt reads the file /www/hello.txt.
Message HTTPD001I names the document root when HTTPD is ready (“What the Console Shows”). A request for a file that HTTPD cannot open gets the same answer as a request for a file that is not there (“A File That Is Not There”).
Two parts make the document root:
- A disk image. The UFS file system lives in an MVS data set. The release of HTTPD includes an image with the welcome page. You build an image of your own with the host tool
ufsd-utils(“Building a Web Root Image”). - A mount. UFSD attaches the image to the path
/www. The mount is a statement in the Parmlib member of UFSD, not of HTTPD (“Mounting the Image”).
The keyword DOCROOT has three rules. The value must start with a slash, or HTTPD ignores it without a message and keeps the old value. HTTPD removes one slash at the end of a longer value. HTTPD keeps at most 127 characters. The Reference has the details.
Building a Web Root Image
To publish your own files, build an image on a workstation. The host tool ufsd-utils of UFSD does it in three commands. The first creates an empty image. The second copies a directory tree into it. The third lists what is in it:
$ ufsd-utils create httpd-webroot.img --size 1M --owner IBMUSER --group SYSPROG
Creating httpd-webroot.img (1M, blksize=4096, inodes=10.0%)
Volume size: 256 blocks (1.00 MB)
Block size: 4096 bytes
Inode blocks: 2 (64 inodes)
Data blocks: 252 (free: 251)
Root owner: IBMUSER/SYSPROG
Format: UFS370 v1 (time64 timestamps)
Upload to MVS: ufsd-utils upload httpd-webroot.img --dsn YOUR.DATASET.NAME
Done.
$ ufsd-utils cp -r static/ httpd-webroot.img:/
README.txt -> /README.txt (36 bytes, txt)
mkdir /admin
report.txt -> /admin/report.txt (50 bytes, txt)
mkdir /css
site.css -> /css/site.css (67 bytes, txt)
data.json -> /data.json (34 bytes, txt)
mkdir /denied
data.txt -> /denied/data.txt (50 bytes, txt)
mkdir /docs
index.html -> /docs/index.html (131 bytes, txt)
manual.txt -> /docs/manual.txt (85 bytes, txt)
mkdir /empty
mkdir /form
page.html -> /form/page.html (111 bytes, txt)
hello.txt -> /hello.txt (61 bytes, txt)
index.html -> /index.html (3573 bytes, txt)
logo.png -> /logo.png (70 bytes, bin)
mkdir /private
secret.txt -> /private/secret.txt (43 bytes, txt)
mkdir /pub
index.html -> /pub/index.html (98 bytes, txt)
notice.txt -> /pub/notice.txt (23 bytes, txt)
mkdir /token
api.txt -> /token/api.txt (38 bytes, txt)
$ ufsd-utils ls -l httpd-webroot.img:/
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 .
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 ..
-rwxr-xr-x 1 IBMUSER SYSPROG 36 2026 Oct 27 05:42 README.txt
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 admin
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 css
-rwxr-xr-x 1 IBMUSER SYSPROG 34 2026 Oct 27 05:42 data.json
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 denied
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 docs
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 empty
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 form
-rwxr-xr-x 1 IBMUSER SYSPROG 61 2026 Oct 27 05:42 hello.txt
-rwxr-xr-x 1 IBMUSER SYSPROG 3573 2026 Oct 27 05:42 index.html
-rwxr-xr-x 1 IBMUSER SYSPROG 70 2026 Oct 27 05:42 logo.png
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 private
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 pub
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 token
$ ufsd-utils ls -l httpd-webroot.img:/docs
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 .
drwxr-xr-x 2 IBMUSER SYSPROG 128 2026 Oct 27 05:42 ..
-rwxr-xr-x 1 IBMUSER SYSPROG 131 2026 Oct 27 05:42 index.html
-rwxr-xr-x 1 IBMUSER SYSPROG 85 2026 Oct 27 05:42 manual.txt
Read the output of the first command as follows. The image is 1 MB. It has 256 blocks of 4096 bytes, and 2 of them hold the inode table with room for 64 inodes. --owner and --group set the owner and the group of the root directory. The size and the number of inodes limit how many files and how much data the image holds. Use --size to make it larger, and see the UFSD User’s Guide for the other options.
The output of cp -r has one line for each file and each directory. At the end of each file line the tool says txt or bin. It stores a text file in EBCDIC, in the code page IBM-1047, and a binary file as it is. HTTPD translates a UFS text file back with the same table (“Text, Binary and the Code Page”).
The create command suggests the next step, uploading the image with ufsd-utils upload. The data set that takes the image is a sequential data set with the record format U and a block size of 4096, the block size of the image. The job HTTPWEBR in the sample library allocates such a data set under the name HTTPD.WEBROOT.UFS. The upload must be binary. Chapter 2, “Installing HTTPD” has the whole procedure, with the installation of the image that ships with HTTPD.
Mounting the Image
UFSD mounts the image at the start from its own Parmlib member. The statement for the data set above and the default document root is:
MOUNT DSN(HTTPD.WEBROOT.UFS) PATH(/www) MODE(RO)
MODE(RO) mounts the image for reading. HTTPD only reads. The path in the statement must be the value of DOCROOT, letter for letter. Start UFSD before HTTPD, so that the first request finds the file system. Chapter 2, “Installing HTTPD” shows the installation of the image, and the UFSD User’s Guide describes the Parmlib member and the operator commands. UFSD changes an operator command to upper case before it reads it. A mount point such as /www therefore comes from the Parmlib statement (Chapter 2, “Installing HTTPD”).
To replace the content, stop HTTPD and UFSD, upload the new image to the same data set, and start UFSD, then HTTPD. Chapter 8, “Operating HTTPD” describes stopping and starting.
Changing the Document Root
The document root need not be the root of the mounted file system. If the image has a directory docs, the member below serves that directory as the whole site:
PORT=8080
DOCROOT=/www/docs
After the restart, the path / reads /www/docs/index.html:
$ curl -i http://localhost:8080/
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:51:01 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/html
X-Content-Type-Options: nosniff
Transfer-Encoding: chunked
<!DOCTYPE html>
<html><head><title>Documents</title></head>
<body><h1>Documents</h1>
<p>This is docs/index.html.</p></body></html>
The file /www/docs/manual.txt is now the path /manual.txt:
$ curl -i http://localhost:8080/manual.txt
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:51:01 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/plain
X-Content-Type-Options: nosniff
Content-Length: 85
HTTPD manual draft
==================
The server serves this file from the UFS root.
A file outside the new root is not found, although it is in the image:
$ curl -i http://localhost:8080/hello.txt
HTTP/1.1 404 Not Found
Date: Tue, 27 Oct 2026 05:51:02 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
404 document "/hello.txt" not found
The file /www/hello.txt exists, but the new document root is /www/docs. A change of DOCROOT takes effect at the next start of HTTPD (Chapter 4, “Configuring HTTPD”).
Directory Requests
A path that ends in a slash names a directory. HTTPD does not list a directory. It looks for the file index.html in it, and if that is not there, for default.html. A directory with an index file answers with the file:
$ curl -i http://localhost:8080/docs/
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:41:42 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/html
X-Content-Type-Options: nosniff
Transfer-Encoding: chunked
<!DOCTYPE html>
<html><head><title>Documents</title></head>
<body><h1>Documents</h1>
<p>This is docs/index.html.</p></body></html>
A directory without index.html and default.html gets a 404. The text repeats the path of the request:
$ curl -i http://localhost:8080/empty/
HTTP/1.1 404 Not Found
Date: Tue, 27 Oct 2026 05:41:42 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
404 document "/empty/" not found
A directory in a path without the closing slash is not a file, and HTTPD does not add the slash for the client. It does not answer with a redirect:
$ curl -i http://localhost:8080/docs
HTTP/1.1 404 Not Found
Date: Tue, 27 Oct 2026 05:41:42 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
404 document "/docs" not found
So a link to a directory has to end in a slash. The path /docs gets the answer above, and the path /docs/ gets the index file.
Content Types
HTTPD chooses the Content-Type from the extension of the file name: the text after the last dot in the last part of the path. If that part has no dot, HTTPD looks at the whole path. The comparison ignores case, so LOGO.PNG and logo.png are the same.
| Extension | Content-Type | Sent as |
html, htm | text/html | text |
css | text/css | text |
js | application/x-javascript | text |
txt | text/plain | text |
xml | text/xml | text |
svg | image/svg+xml | text |
png | image/png | binary |
jpg, jpeg | image/jpeg | binary |
gif | image/gif | binary |
ico | image/x-icon | binary |
pdf | application/pdf | binary |
zip | application/zip | binary |
| any other, or none | text/plain | text |
Table 23. Some content types
The whole table is in “HTTP Behaviour and Limits” in the HTTPD Reference. Three captures show the effect. A style sheet is text and has its type:
$ curl -i http://localhost:8080/css/site.css
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:41:42 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/css
X-Content-Type-Options: nosniff
Content-Length: 67
body { font-family: sans-serif; margin: 2em; }
h1 { color: #036; }
A PNG image has its type, and the body is sent as it is stored. The capture shows only the headers:
$ curl -s -D - -o /dev/null http://localhost:8080/logo.png
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:41:43 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: image/png
X-Content-Type-Options: nosniff
Content-Length: 70
A file whose extension is not in the table is sent as text/plain, also when the file is JSON:
$ curl -i http://localhost:8080/data.json
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:41:42 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/plain
X-Content-Type-Options: nosniff
Content-Length: 34
{"name": "httpd", "static": true}
Text, Binary and the Code Page
The last column of the table says how HTTPD sends the body.
- Text. HTTPD translates every byte from EBCDIC to ASCII. It uses the table for IBM-1047, whatever the Parmlib keyword
CODEPAGEsays. - Binary. HTTPD sends the bytes as they are stored in the image.
The keyword CODEPAGE selects the table for the status line, the headers and the text of the responses that HTTPD writes itself, and for the decoding of the request (see “Paths” below). It has no effect on the content of a file. So a text file in the image has to be in IBM-1047. The tool ufsd-utils writes the files of a text type in that code page (“Building a Web Root Image”). The chapter Chapter 4, “Configuring HTTPD” tells how to set CODEPAGE.
Server Side Includes
HTTPD scans a file of the type text/html or text/x-server-parsed-html for server side includes while it sends it. These are the extensions htm, html, shtm and shtml. A directive such as <!--#include virtual="/part.html" --> is replaced by the text it names. Because the final size is not known, the response has no Content-Length and uses chunked transfer, as the response of the welcome page in “Getting the Welcome Page” does. The directives and their limits are in “HTTP Behaviour and Limits” in the HTTPD Reference.
Any other file, also a file with the extension txt, is sent without a scan.
Paths
HTTPD does five things to the path of a request before it joins it to the document root:
- It cuts off the query. The text after the first question mark is not part of the file name.
- It decodes the path. Each
%xxbecomes the character with that hexadecimal value, translated through the table ofCODEPAGE. A plus sign stays a plus sign in the path. To ask for a blank in a file name, write%20. A percent sign that is not followed by two hexadecimal digits, and the escape%00, stay as they are. - It refuses a path with two dots in a row. The check is on the decoded path, so
%2e%2edoes not help either. The answer is a 404. A file name that has two dots in a row, such asa..b.txt, cannot be served. - It cuts the path to 255 characters, and the joined name of the document root and the path to 255 characters. The client is not told.
- It looks at the extension for the content type (“Content Types”).
The answer for a path that does not name a file is the 404 that the first chapter shows. Its text contains the decoded path:
$ curl -i http://localhost:8080/nothere.html
HTTP/1.1 404 Not Found
Date: Tue, 27 Oct 2026 05:41:42 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
404 document "/nothere.html" not found
What Is Not Supported
A static file is read-only for the client and always whole. HTTPD answers a GET and a HEAD. It does not answer anything else for a file.
HEAD. The curl option -I sends a HEAD request, as “Choosing a Client” shows. HTTPD answers with the status and the headers that a GET gets, and sends no body. A file that is not there gets the 404 of a GET, with no body:
$ curl -I http://localhost:8080/nothere.html
HTTP/1.1 404 Not Found
Date: Tue, 27 Oct 2026 17:11:59 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/plain
The connection stays open, as it does after a GET (“Two Requests on One Connection”). With curl -v -I and two URLs, the second HEAD uses the connection of the first:
$ curl -v -I http://localhost:8080/hello.txt http://localhost:8080/hello.txt
* Host localhost:8080 was resolved.
* IPv6: ::1
* IPv4: 127.0.0.1
* Trying [::1]:8080...
* Connected to localhost (::1) port 8080
* using HTTP/1.x
> HEAD /hello.txt HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Date: Tue, 27 Oct 2026 17:11:59 GMT
< Server: HTTPD Server
< X-Powered-By: MVSLOVERS
< Connection: keep-alive
< Content-Type: text/plain
< X-Content-Type-Options: nosniff
< Content-Length: 61
<
* Connection #0 to host localhost left intact
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 17:11:59 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/plain
X-Content-Type-Options: nosniff
Content-Length: 61
* Re-using existing http: connection with host localhost
> HEAD /hello.txt HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/8.14.1
> Accept: */*
>
* Request completely sent off
< HTTP/1.1 200 OK
< Date: Tue, 27 Oct 2026 17:11:59 GMT
< Server: HTTPD Server
< X-Powered-By: MVSLOVERS
< Connection: keep-alive
< Content-Type: text/plain
< X-Content-Type-Options: nosniff
< Content-Length: 61
<
* Connection #0 to host localhost left intact
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 17:11:59 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/plain
X-Content-Type-Options: nosniff
Content-Length: 61
A HEAD gets a Content-Length only where a GET gets one. An HTML file has none, because HTTPD looks for server-side includes in it (“Server Side Includes”). A HEAD for such a file has neither a length nor chunked transfer:
$ curl -I http://localhost:8080/docs/
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 17:11:59 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/html
X-Content-Type-Options: nosniff
The HEAD answer of HTTPD 4.4.0 and earlier is 501 Not Implemented.
Other methods. POST, PUT and DELETE for a static file get 501 Not Implemented. The three methods:
$ curl -i -X POST -d x=1 http://localhost:8080/hello.txt
HTTP/1.1 501 Not Implemented
Date: Tue, 27 Oct 2026 05:41:53 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: close
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
501 Not Implemented
$ curl -i -X PUT -d x=1 http://localhost:8080/hello.txt
HTTP/1.1 501 Not Implemented
Date: Tue, 27 Oct 2026 05:41:53 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: close
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
501 Not Implemented
$ curl -i -X DELETE http://localhost:8080/hello.txt
HTTP/1.1 501 Not Implemented
Date: Tue, 27 Oct 2026 05:41:53 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
501 Not Implemented
The responses to POST and PUT have Connection: close because the requests have a body. The response to DELETE, which has none, keeps the connection. A client cannot change a file in the image over HTTP. Replace the image to change the content (“Mounting the Image”).
A method that HTTPD does not know at all gets 405 Method Not Allowed and the connection is closed. The answer has no Allow header. HTTPD sends the 405 before it looks at the route, so it is the same for every path:
$ curl -i -X OPTIONS http://localhost:8080/hello.txt
HTTP/1.1 405 Method Not Allowed
Date: Tue, 27 Oct 2026 05:41:53 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: close
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
405 Method Not Allowed
Ranges. HTTPD does not look at a Range header. It sends the whole file with status 200 and no Content-Range header:
$ curl -i -H "Range: bytes=0-9" http://localhost:8080/hello.txt
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:41:53 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/plain
X-Content-Type-Options: nosniff
Content-Length: 61
Hello from the HTTPD document root.
This file is plain text.
Conditional requests. HTTPD does not look at If-Modified-Since either. It never answers with 304, and it sends no Last-Modified or ETag header:
$ curl -i -H "If-Modified-Since: Tue, 27 Oct 2026 00:00:00 GMT" http://localhost:8080/hello.txt
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:41:53 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/plain
X-Content-Type-Options: nosniff
Content-Length: 61
Hello from the HTTPD document root.
This file is plain text.
A client that sends these headers gets the whole file each time. A server module on a route with a program decides about the methods GET, HEAD, POST, PUT and DELETE and about the headers for its own paths. Chapter 5, “Routes and Server Modules” tells how routes are matched.
Static Locations
A request that no route claims is served from the document root, and nobody needs to log in for it. To ask for a login for a part of the tree, name it in a LOC= route. A LOC= route has no program. HTTPD serves the path as a static file, as in this chapter, after the check of the route has passed. The Parmlib member of the test system has these lines:
LOC=/pub/* AUTH=NONE LOC=/private/* AUTH=BASIC LOC=/admin/* AUTH=BASIC RES=FACILITY:HTTPD.ADMIN LOC=/denied/* AUTH=BASIC RES=FACILITY:HTTPD.DENIED
A path under /pub/ is public:
$ curl -i http://localhost:8080/pub/notice.txt
HTTP/1.1 200 OK
Date: Tue, 27 Oct 2026 05:52:44 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Content-Type: text/plain
X-Content-Type-Options: nosniff
Content-Length: 23
This notice is public.
A path under /private/ asks for a login, and a request without credentials gets a 401 with a WWW-Authenticate header:
$ curl -i http://localhost:8080/private/secret.txt
HTTP/1.1 401 Unauthorized
Date: Tue, 27 Oct 2026 05:52:44 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
WWW-Authenticate: Basic realm="MVS.EXAMPLE"
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
401 Unauthorized
A user who logs in but has no access to the resource of the route gets a 403:
$ curl -i -u IBMUSER:****** http://localhost:8080/denied/data.txt
HTTP/1.1 403 Forbidden
Date: Tue, 27 Oct 2026 05:52:48 GMT
Server: HTTPD Server
X-Powered-By: MVSLOVERS
Connection: keep-alive
Cache-Control: no-store
Content-Type: text/plain
Transfer-Encoding: chunked
403 Forbidden
The syntax of the routes and the order in which HTTPD tries them are in Chapter 5, “Routes and Server Modules”. The modes of AUTH= and the resource check are in Chapter 6, “Authentication and Security”.
When UFSD Is Not There
HTTPD reads static files through UFSD. It creates the control block of its file system when it starts. This step does not contact UFSD, and HTTPD does not check that UFSD runs. The message HTTPD044W UNABLE TO INITIALIZE FILE SYSTEM says that HTTPD could not create that block. It does not say that UFSD is down.
HTTPD asks UFSD for a session when it opens a file, for each request. In each of these cases HTTPD gets no file, and the answer is the 404 of “A File That Is Not There”:
- HTTPD cannot get a session from UFSD.
- Nothing is mounted at the document root, or the mount is at another path.
- The file or the directory is not in the image.
The Parmlib keyword UFS=0 switches the file system off. HTTPD then serves no file, and every path that no route claims gets a 404. Leave the keyword at its default if you want to serve files. A route with a program is dispatched without the file system.
When every static request gets a 404, check in this order: that UFSD runs, that the image is mounted (the operator command F UFSD,MOUNT LIST shows the mounts), that the mount point is the value of DOCROOT, and that the file is in the image. See also Chapter 12, “Troubleshooting”.
What Can Go Wrong
- A binary file arrives damaged. Its extension is not in the table, so HTTPD sent it as text (“Content Types”).
- Text shows wrong characters. The file in the image is not in IBM-1047, or the upload of the image was not binary.
- A link to a directory gives 404. The link has no closing slash (“Directory Requests”).
- A file with a double dot in its name is not found. HTTPD refuses any path with two dots in a row (“Paths”).
- A browser shows an old copy of a file. Among the files, only HTML documents get
Cache-Control: no-store, and HTTPD sends noLast-ModifiedorETagfor any file. The browser decides by its own rules for the others. - The change of
DOCROOThas no effect. HTTPD reads the Parmlib at start only. Restart it (Chapter 8, “Operating HTTPD”).