-
Notifications
You must be signed in to change notification settings - Fork 316
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
Cannot serve css/js static files big size #1064
Comments
I'm unable to replicate this as being a problem with large static files. The error mentions that the file has changed during the request, which does appear to be the issue. I'll look into it.
Besides the error in the logs, does the large CSS file load properly in the browser? |
Trying to access directly to the file in the browser: |
I even delete some content to the css file it loads properly when it is about 64kb |
Hi @tonychuuy Seeing as we are unable to reproduce this behaviour, here is how you may be able to debug this a little further... I'll demonstrate with an example... (this assumes your running on Linux...) Simple Unit config {
"listeners": {
"[::1]:8080": {
"pass": "routes"
}
},
"routes": [
{
"match": {
"uri": "*"
},
"action": {
"share": "/tmp/unit-share$uri"
}
}
]
} Create a 1MiB file in the share directory $ dd if=/dev/zero of=1m bs=1 count=$((1024*1024))
1048576+0 records in
1048576+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 2.49936 s, 420 kB/s Configure unit with the above config (in the following I'm assuming unit is just running as yourself...) Find the PID of the 'unit: router' process, something like
Then start a strace(1) on it
Where the PID (-p option) is the one you got above. Now hit Unit with a request for that file, something like
So you see it fully retrieved the 1MiB file. While the strace(1) output shows [{events=EPOLLIN, data={u32=1073746752, u64=140717087265600}}], 32, -1) = 1
[pid 338447] accept4(11, {sa_family=AF_INET6, sin6_port=htons(39486), sin6_flowinfo=htonl(0), inet_pton(AF_INET6, "::1", &sin6_addr), sin6_scope_id=0}, [28], SOCK_NONBLOCK) = 32
[pid 338447] accept4(11, 0x7ffb40001808, [28], SOCK_NONBLOCK) = -1 EAGAIN (Resource temporarily unavailable)
[pid 338447] epoll_ctl(16, EPOLL_CTL_ADD, 32, {events=EPOLLIN|EPOLLRDHUP|EPOLLET, data={u32=1073752128, u64=140717087270976}}) = 0 Unit accepted a connection from the client and will now wait for the request...
Unit received the request from the client. opened the requested file and we can see from the fstatat((2) (newfstatat) that the file size is indeed 1MiB (st_size=1048576)
Unit reads 256KiB worth of data from the file and sends it to the client...
and again...
and again...
and sends the final 256KiB of data back to the client...
Then some final clean up... The return values of the pread(2) system calls should add up to our file size here of 1048576, as likewise should the return values of the writev(2) system calls. So perhaps if you are able to use the above method when trying to retrieve a problematic file and show the strace(1) output?. |
I'm using the docker image unit:1.31.1-php8.2, I'm trying to apply this test inside the running container, by using docker compose exec |
I installed procps and strace in the docker image, but now i'm getting the following error:
|
Using the top option from docker and applying strace outside docker works for the test:
|
The same test with my config and the css file:
|
@tonychuuy out of curiosity, is this a Laravel app running the Telescope package? |
Yes it is. |
Thanks. I'll try to figure out whether there's anything weird about that file in particular 🤔 . I managed to reproduce the error by actually continually changing the size of a file being shared, though it doesn't look like that's happening in your case. This happens 100% of the time you're trying to access that file? |
Yes 100%, I can access telescope but it renders horrible because JS/CSS is not loaded. |
Thanks for managing to do that test! Yes, I can seem something has gone very wrong. Let me see if I can replicate it with a file of the same size as yours. What kind of filesystem are these files, or I guess the docker image stored on? Any networking involved? e.g nfs/cifs etc... |
This is my config for docker: docker-compose.yml
I have more services like mysql and redis. Dockerfile
|
Thanks, not really familiar with docker myself...
OK...
I wonder where this mmap(2) comes from?
So we wanted to read 128KiB, but only managed a little under 64KiB. Just to double check some things, because this is one of these things that just doesn't make any sense, this is a regular file right?, not a pipe/socket or some such? This also happens with any file over a certain size? Another test to do here would be if you could, when unit is all up and running, copy that file to some other location and check its copied size. Actually could you also check if this happens if you don't have the PHP application running, I.e remove the application part from the unit config to rule it out from doing something nefarious... |
I think is a regular file, and as I said in another comment, I deleted some content of the same file to reach 64kb and it loads correctly.
Any file bigger than 64kb, js or css files are the ones I have tested.
I removed the php application and accessing the file directly in the browser same error is presented, other small files are loaded correctly. |
Yes it is... When you did the 1MiB file test, that was effectively the same environment as the one your having the issue with? Are you able to put that 1MiB in the same directory as the css file and try pulling both with curl? |
It was the same environment, I put the file in the /tmp directory. |
Is /tmp tmpfs?
Could you try putting it with the other files? |
I just did that test:
|
Thinking this is a windows issue, I'm on windows using WSL with docker but the files are actually in the windows system. Let me try in a mac. |
Trying the same config in a mac with docker desktop, it works perfectly, all the files from Telescope are loaded properly. Unfortunately I need to work on windows because this is an old mac and it is super slow. |
Someone on Reddit appears to have had a the same issue. While they don't mention they're running Unit, the error message is identical so I suspect they are: https://www.reddit.com/r/docker/comments/tjomqm/file_has_changed_while_sending_response_to_a/ |
Good find. I know nothing about Windows or WSL. But are we talking about WSL version 1 or 2 here? And what version of Windows? |
WSL version: 2.0.14.0 |
I will give it a try on my WSL2 Ubuntu system. So you are saying the files are on C / D drive not in the WSL Linux file system? How do you start the docker compose service? From the WSL2 cli or from docker desktop? |
From your
Interesting that it again only read 65512 bytes, same as when you tried the css file. Your initial 1MiB file test worked I assume because it was being served out of tmpfs which is effectively RAM. OK, so you're using WSL 2, I think I've read that it uses the 9p filesystem protocol, which is a network protocol, which could perhaps explain why you're seeing short reads... Need to try and devise some way of testing that theory... |
cli inside WSL ubuntu |
Hmm, interesting
|
@ac000 correct! That's why I am ALWAYS using the Linux file system for all my project data as the 9P Client / Server can be very slow and causes issues BUT I have worked with projects and Unit and can't remember this issue. I will just try reproduce and share the findiges from my WSL2 Ubuntu and Docker Desktop setup in a couple of minutes / hour. |
@ac000 let me know if you need anything. I have all the things set up 👍🏼 |
If using 9p is optional, can you try taking that out of the equation? Alternatively you could try this patch diff --git a/src/nxt_http_static.c b/src/nxt_http_static.c
index e51ba6b0..14420669 100644
--- a/src/nxt_http_static.c
+++ b/src/nxt_http_static.c
@@ -879,12 +879,7 @@ nxt_http_static_buf_completion(nxt_task_t *task, void *obj, void *data)
n = nxt_file_read(fb->file, b->mem.start, size, fb->file_pos);
- if (n != size) {
- if (n >= 0) {
- nxt_log(task, NXT_LOG_ERR, "file \"%FN\" has changed "
- "while sending response to a client", fb->file->name);
- }
-
+ if (n == -1) {
nxt_http_request_error_handler(task, r, r->proto.any);
goto clean;
} |
Where do I change this? |
@ac000 @tonychuuy it works for me having the files inside the Linux filesystem outside the mounted windows shares. So taking 9P out will solve it. Testing more |
@tippexs But then I need to work completely on ubuntu right, how do you edit your files with an IDE installed on windows? |
Taking 9p out of the equation may be easier for you. |
I do that using the Ubuntu mount on my windows box. Let me drop you a couple of screenshots. This is how I do it. I am also watching this thread for while microsoft/WSL#4197 So from my point of view I had nothing but issues with the 9P Network Filesystem. I am always working on the Linux file system and using the wsl target in windows. |
@tippexs Amazing, everything is loaded correctly, but phpstorm IDE is so slow to open/indexing the files from ubuntu. |
I have just tested it on my end. My Environment
I have copied the project files to I have started the Unit Container from inside WSL and the curl just works but we have just checked the output of drvfs on /mnt/d type 9p (rw,noatime,dirsync,aname=drvfs;path=D:\;uid=1000;gid=1000;symlinkroot=/mnt/,mmap,access=client,msize=262144,trans=virtio) See the |
Take a look at this https://www.jetbrains.com/help/phpstorm/how-to-use-wsl-development-environment-in-product.html Yes the initial indexing might be slower but after that PHPStorm should work just super smooth. I am more than happy to chat more about a dev environment using WSL2. Happy to move to a Discussion OR drop me message on Discord: h3x0ne |
@tippexs Thanks, I will wait for the indexing process, if the patch is applied I maybe return to the windows system since this is a development environment. |
OK, so I was able to reproduce this locally by exporting a directory into a QEMU/KVM virtual machine running Fedora using the 9P protocol via
In the guest I mounted it thus
Note I set the msize to 65512 After pointing Unit to this directory and executing (in the guest)
Where tfile is a file of 149922 bytes in length, I got the expected failure
And looking at the strace output
We got the request from the client, opened the requested file and stat'd it...
We asked to read 131072 bytes but only got 61440
At which point the check in unit that if we read less then we asked for kicks in and aborts the transfer... Now trying it with the above patch which removes that check
All good, lets check the strace output
Again, we got the request from the client, opened the requested file and stat'd it (oh and just to be clear, we stat(2) the file to get its size).
So, now we do two reads totalling 80290 bytes and send that back to the client along with some headers.
We do another two reads (giving a total of 149922 bytes read) and send that to the client and that's us done. This was certainly a fun one to debug ;) I'll turn the patch into a PR... |
On GH, @tonychuuy reported an issue when using Units 'share' action they would get the following error in the unit log 2024/01/15 17:53:41 [error] 49#52 *103 file "/var/www/html/public/vendor/telescope/app.css" has changed while sending response to a client This would happen when trying to serve files over a certain size and the requested file would not be sent. This is due to a somewhat bogus check in nxt_http_static_buf_completion() I say bogus because it's not clear what the check is trying to accomplish and the error message is not entirely accurate either. The check in question goes like n = pread(file->fd, buf, size, offset); return n; ... if (n != size) { if (n >= 0) { /* log file changed error and finish */ } /* log general error and finish */ } If the number of bytes read is not what we asked for and is > -1 (i.e not an error) then it says the file has changed, but really it only checks if the file has _shrunk_ (we can't get back _more_ bytes than we asked for) since it was stat'd. This is what happens recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 We get a request from a client, open the requested file and stat(2) it to get the file size. We would then go into a pread/writev loop reading the file data and sending it to the client until it's all been sent. However what was happening in this case was this (showing a dummy file of 149922 bytes) pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 write(2, "2024/01/17 15:30:50 [error] 1849"..., 109) = 109 We wanted to read 131072 bytes but only read 61440 bytes, the above check triggered and the file transfer was aborted and the above error message logged. Normally for a regular file you will only get less bytes than asked for if the read call is interrupted by a signal or you're near the end of file. There is however at least another situation where this may happen, if the file in question is being served from a network filesystem. It turns out that was indeed the case here, the files where being served over the 9P filesystem protocol. Unit was running in a docker container in an Ubuntu VM under Windows/WSL2 and the files where being passed through to the VM from Windows over 9P. Whatever the intention of this check, it is clearly causing issues in real world scenarios. If it was really desired to check if the had changed since it was opened/stat'd then it would require a different methodology and be a patch for another day. But as it stands this current check does more harm than good, so lets just remove it. With it removed we now get for the above test file recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f367817b000 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 18850, 61440) = 18850 writev(22, [{iov_base="HTTP/1.1 200 OK\r\nLast-Modified: "..., iov_len=171}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=18850}], 3) = 80461 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 69632, 80290) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, 141730) = 8192 close(23) = 0 writev(22, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=8192}], 2) = 69632 So we can see we do two pread(2)s's and a writev(2), then another two pread(2)s and another writev(2) and all the file data has been read and sent to the client. Reported-by: tonychuuy <https://github.com/tonychuuy> Link: <https://en.wikipedia.org/wiki/9P_(protocol)> Fixes: 08a8d15 ("Basic support for serving static files.") Closes: nginx#1064 Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
On GH, @tonychuuy reported an issue when using Units 'share' action they would get the following error in the unit log 2024/01/15 17:53:41 [error] 49#52 *103 file "/var/www/html/public/vendor/telescope/app.css" has changed while sending response to a client This would happen when trying to serve files over a certain size and the requested file would not be sent. This is due to a somewhat bogus check in nxt_http_static_buf_completion() I say bogus because it's not clear what the check is trying to accomplish and the error message is not entirely accurate either. The check in question goes like n = pread(file->fd, buf, size, offset); return n; ... if (n != size) { if (n >= 0) { /* log file changed error and finish */ /* >> Problem is here << */ } /* log general error and finish */ } If the number of bytes read is not what we asked for and is > -1 (i.e not an error) then it says the file has changed, but really it only checks if the file has _shrunk_ (we can't get back _more_ bytes than we asked for) since it was stat'd. This is what happens recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 We get a request from a client, open the requested file and stat(2) it to get the file size. We would then go into a pread/writev loop reading the file data and sending it to the client until it's all been sent. However what was happening in this case was this (showing a dummy file of 149922 bytes) pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 write(2, "2024/01/17 15:30:50 [error] 1849"..., 109) = 109 We wanted to read 131072 bytes but only read 61440 bytes, the above check triggered and the file transfer was aborted and the above error message logged. Normally for a regular file you will only get less bytes than asked for if the read call is interrupted by a signal or you're near the end of file. There is however at least another situation where this may happen, if the file in question is being served from a network filesystem. It turns out that was indeed the case here, the files where being served over the 9P filesystem protocol. Unit was running in a docker container in an Ubuntu VM under Windows/WSL2 and the files where being passed through to the VM from Windows over 9P. Whatever the intention of this check, it is clearly causing issues in real world scenarios. If it was really desired to check if the had changed since it was opened/stat'd then it would require a different methodology and be a patch for another day. But as it stands this current check does more harm than good, so lets just remove it. With it removed we now get for the above test file recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f367817b000 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 18850, 61440) = 18850 writev(22, [{iov_base="HTTP/1.1 200 OK\r\nLast-Modified: "..., iov_len=171}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=18850}], 3) = 80461 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 69632, 80290) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, 141730) = 8192 close(23) = 0 writev(22, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=8192}], 2) = 69632 So we can see we do two pread(2)s's and a writev(2), then another two pread(2)s and another writev(2) and all the file data has been read and sent to the client. Reported-by: tonychuuy <https://github.com/tonychuuy> Link: <https://en.wikipedia.org/wiki/9P_(protocol)> Fixes: 08a8d15 ("Basic support for serving static files.") Closes: nginx#1064 Reviewed-by: Zhidao Hong <z.hong@f5.com> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
On GH, @tonychuuy reported an issue when using Units 'share' action they would get the following error in the unit log 2024/01/15 17:53:41 [error] 49#52 *103 file "/var/www/html/public/vendor/telescope/app.css" has changed while sending response to a client This would happen when trying to serve files over a certain size and the requested file would not be sent. This is due to a somewhat bogus check in nxt_http_static_buf_completion() I say bogus because it's not clear what the check is trying to accomplish and the error message is not entirely accurate either. The check in question goes like n = pread(file->fd, buf, size, offset); return n; ... if (n != size) { if (n >= 0) { /* log file changed error and finish */ /* >> Problem is here << */ } /* log general error and finish */ } If the number of bytes read is not what we asked for and is > -1 (i.e not an error) then it says the file has changed, but really it only checks if the file has _shrunk_ (we can't get back _more_ bytes than we asked for) since it was stat'd. This is what happens recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 We get a request from a client, open the requested file and stat(2) it to get the file size. We would then go into a pread/writev loop reading the file data and sending it to the client until it's all been sent. However what was happening in this case was this (showing a dummy file of 149922 bytes) pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 write(2, "2024/01/17 15:30:50 [error] 1849"..., 109) = 109 We wanted to read 131072 bytes but only read 61440 bytes, the above check triggered and the file transfer was aborted and the above error message logged. Normally for a regular file you will only get less bytes than asked for if the read call is interrupted by a signal or you're near the end of file. There is however at least another situation where this may happen, if the file in question is being served from a network filesystem. It turns out that was indeed the case here, the files where being served over the 9P filesystem protocol. Unit was running in a docker container in an Ubuntu VM under Windows/WSL2 and the files where being passed through to the VM from Windows over 9P. Whatever the intention of this check, it is clearly causing issues in real world scenarios. If it was really desired to check if the had changed since it was opened/stat'd then it would require a different methodology and be a patch for another day. But as it stands this current check does more harm than good, so lets just remove it. With it removed we now get for the above test file recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f367817b000 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 18850, 61440) = 18850 writev(22, [{iov_base="HTTP/1.1 200 OK\r\nLast-Modified: "..., iov_len=171}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=18850}], 3) = 80461 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 69632, 80290) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, 141730) = 8192 close(23) = 0 writev(22, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=8192}], 2) = 69632 So we can see we do two pread(2)s's and a writev(2), then another two pread(2)s and another writev(2) and all the file data has been read and sent to the client. Reported-by: tonychuuy <https://github.com/tonychuuy> Link: <https://en.wikipedia.org/wiki/9P_(protocol)> Fixes: 08a8d15 ("Basic support for serving static files.") Closes: nginx#1064 Reviewed-by: Zhidao Hong <z.hong@f5.com> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
On GH, @tonychuuy reported an issue when using Units 'share' action they would get the following error in the unit log 2024/01/15 17:53:41 [error] 49#52 *103 file "/var/www/html/public/vendor/telescope/app.css" has changed while sending response to a client This would happen when trying to serve files over a certain size and the requested file would not be sent. This is due to a somewhat bogus check in nxt_http_static_buf_completion() I say bogus because it's not clear what the check is trying to accomplish and the error message is not entirely accurate either. The check in question goes like n = pread(file->fd, buf, size, offset); return n; ... if (n != size) { if (n >= 0) { /* log file changed error and finish */ /* >> Problem is here << */ } /* log general error and finish */ } If the number of bytes read is not what we asked for and is > -1 (i.e not an error) then it says the file has changed, but really it only checks if the file has _shrunk_ (we can't get back _more_ bytes than we asked for) since it was stat'd. This is what happens recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 We get a request from a client, open the requested file and stat(2) it to get the file size. We would then go into a pread/writev loop reading the file data and sending it to the client until it's all been sent. However what was happening in this case was this (showing a dummy file of 149922 bytes) pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 write(2, "2024/01/17 15:30:50 [error] 1849"..., 109) = 109 We wanted to read 131072 bytes but only read 61440 bytes, the above check triggered and the file transfer was aborted and the above error message logged. Normally for a regular file you will only get less bytes than asked for if the read call is interrupted by a signal or you're near the end of file. There is however at least another situation where this may happen, if the file in question is being served from a network filesystem. It turns out that was indeed the case here, the files where being served over the 9P filesystem protocol. Unit was running in a docker container in an Ubuntu VM under Windows/WSL2 and the files where being passed through to the VM from Windows over 9P. Whatever the intention of this check, it is clearly causing issues in real world scenarios. If it was really desired to check if the had changed since it was opened/stat'd then it would require a different methodology and be a patch for another day. But as it stands this current check does more harm than good, so lets just remove it. With it removed we now get for the above test file recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f367817b000 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 18850, 61440) = 18850 writev(22, [{iov_base="HTTP/1.1 200 OK\r\nLast-Modified: "..., iov_len=171}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=18850}], 3) = 80461 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 69632, 80290) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, 141730) = 8192 close(23) = 0 writev(22, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=8192}], 2) = 69632 So we can see we do two pread(2)s's and a writev(2), then another two pread(2)s and another writev(2) and all the file data has been read and sent to the client. Reported-by: tonychuuy <https://github.com/tonychuuy> Link: <https://en.wikipedia.org/wiki/9P_(protocol)> Fixes: 08a8d15 ("Basic support for serving static files.") Closes: nginx#1064 Reviewed-by: Zhidao Hong <z.hong@f5.com> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
On GH, @tonychuuy reported an issue when using Units 'share' action they would get the following error in the unit log 2024/01/15 17:53:41 [error] 49#52 *103 file "/var/www/html/public/vendor/telescope/app.css" has changed while sending response to a client This would happen when trying to serve files over a certain size and the requested file would not be sent. This is due to a somewhat bogus check in nxt_http_static_buf_completion() I say bogus because it's not clear what the check is trying to accomplish and the error message is not entirely accurate either. The check in question goes like n = pread(file->fd, buf, size, offset); return n; ... if (n != size) { if (n >= 0) { /* log file changed error and finish */ /* >> Problem is here << */ } /* log general error and finish */ } If the number of bytes read is not what we asked for and is > -1 (i.e not an error) then it says the file has changed, but really it only checks if the file has _shrunk_ (we can't get back _more_ bytes than we asked for) since it was stat'd. This is what happens recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 We get a request from a client, open the requested file and stat(2) it to get the file size. We would then go into a pread/writev loop reading the file data and sending it to the client until it's all been sent. However what was happening in this case was this (showing a dummy file of 149922 bytes) pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 write(2, "2024/01/17 15:30:50 [error] 1849"..., 109) = 109 We wanted to read 131072 bytes but only read 61440 bytes, the above check triggered and the file transfer was aborted and the above error message logged. Normally for a regular file you will only get less bytes than asked for if the read call is interrupted by a signal or you're near the end of file. There is however at least another situation where this may happen, if the file in question is being served from a network filesystem. It turns out that was indeed the case here, the files where being served over the 9P filesystem protocol. Unit was running in a docker container in an Ubuntu VM under Windows/WSL2 and the files where being passed through to the VM from Windows over 9P. Whatever the intention of this check, it is clearly causing issues in real world scenarios. If it was really desired to check if the had changed since it was opened/stat'd then it would require a different methodology and be a patch for another day. But as it stands this current check does more harm than good, so lets just remove it. With it removed we now get for the above test file recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f367817b000 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 18850, 61440) = 18850 writev(22, [{iov_base="HTTP/1.1 200 OK\r\nLast-Modified: "..., iov_len=171}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=18850}], 3) = 80461 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 69632, 80290) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, 141730) = 8192 close(23) = 0 writev(22, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=8192}], 2) = 69632 So we can see we do two pread(2)s's and a writev(2), then another two pread(2)s and another writev(2) and all the file data has been read and sent to the client. Reported-by: tonychuuy <https://github.com/tonychuuy> Link: <https://en.wikipedia.org/wiki/9P_(protocol)> Fixes: 08a8d15 ("Basic support for serving static files.") Closes: nginx#1064 Reviewed-by: Zhidao Hong <z.hong@f5.com> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
Thanks for your help in debugging this issue. This fix will appear in the next release of Unit, 1.32 |
On GH, @tonychuuy reported an issue when using Units 'share' action they would get the following error in the unit log 2024/01/15 17:53:41 [error] 49#52 *103 file "/var/www/html/public/vendor/telescope/app.css" has changed while sending response to a client This would happen when trying to serve files over a certain size and the requested file would not be sent. This is due to a somewhat bogus check in nxt_http_static_buf_completion() I say bogus because it's not clear what the check is trying to accomplish and the error message is not entirely accurate either. The check in question goes like n = pread(file->fd, buf, size, offset); return n; ... if (n != size) { if (n >= 0) { /* log file changed error and finish */ /* >> Problem is here << */ } /* log general error and finish */ } If the number of bytes read is not what we asked for and is > -1 (i.e not an error) then it says the file has changed, but really it only checks if the file has _shrunk_ (we can't get back _more_ bytes than we asked for) since it was stat'd. This is what happens recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 We get a request from a client, open the requested file and stat(2) it to get the file size. We would then go into a pread/writev loop reading the file data and sending it to the client until it's all been sent. However what was happening in this case was this (showing a dummy file of 149922 bytes) pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 write(2, "2024/01/17 15:30:50 [error] 1849"..., 109) = 109 We wanted to read 131072 bytes but only read 61440 bytes, the above check triggered and the file transfer was aborted and the above error message logged. Normally for a regular file you will only get less bytes than asked for if the read call is interrupted by a signal or you're near the end of file. There is however at least another situation where this may happen, if the file in question is being served from a network filesystem. It turns out that was indeed the case here, the files where being served over the 9P filesystem protocol. Unit was running in a docker container in an Ubuntu VM under Windows/WSL2 and the files where being passed through to the VM from Windows over 9P. Whatever the intention of this check, it is clearly causing issues in real world scenarios. If it was really desired to check if the had changed since it was opened/stat'd then it would require a different methodology and be a patch for another day. But as it stands this current check does more harm than good, so lets just remove it. With it removed we now get for the above test file recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f367817b000 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 18850, 61440) = 18850 writev(22, [{iov_base="HTTP/1.1 200 OK\r\nLast-Modified: "..., iov_len=171}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=18850}], 3) = 80461 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 69632, 80290) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, 141730) = 8192 close(23) = 0 writev(22, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=8192}], 2) = 69632 So we can see we do two pread(2)s's and a writev(2), then another two pread(2)s and another writev(2) and all the file data has been read and sent to the client. Reported-by: tonychuuy <https://github.com/tonychuuy> Link: <https://en.wikipedia.org/wiki/9P_(protocol)> Fixes: 08a8d15 ("Basic support for serving static files.") Closes: #1064 Reviewed-by: Zhidao Hong <z.hong@f5.com> Reviewed-by: Andrei Zeliankou <zelenkov@nginx.com> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
On GH, @tonychuuy reported an issue when using Units 'share' action they would get the following error in the unit log 2024/01/15 17:53:41 [error] 49#52 *103 file "/var/www/html/public/vendor/telescope/app.css" has changed while sending response to a client This would happen when trying to serve files over a certain size and the requested file would not be sent. This is due to a somewhat bogus check in nxt_http_static_buf_completion() I say bogus because it's not clear what the check is trying to accomplish and the error message is not entirely accurate either. The check in question goes like n = pread(file->fd, buf, size, offset); return n; ... if (n != size) { if (n >= 0) { /* log file changed error and finish */ /* >> Problem is here << */ } /* log general error and finish */ } If the number of bytes read is not what we asked for and is > -1 (i.e not an error) then it says the file has changed, but really it only checks if the file has _shrunk_ (we can't get back _more_ bytes than we asked for) since it was stat'd. This is what happens recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 We get a request from a client, open the requested file and stat(2) it to get the file size. We would then go into a pread/writev loop reading the file data and sending it to the client until it's all been sent. However what was happening in this case was this (showing a dummy file of 149922 bytes) pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 write(2, "2024/01/17 15:30:50 [error] 1849"..., 109) = 109 We wanted to read 131072 bytes but only read 61440 bytes, the above check triggered and the file transfer was aborted and the above error message logged. Normally for a regular file you will only get less bytes than asked for if the read call is interrupted by a signal or you're near the end of file. There is however at least another situation where this may happen, if the file in question is being served from a network filesystem. It turns out that was indeed the case here, the files where being served over the 9P filesystem protocol. Unit was running in a docker container in an Ubuntu VM under Windows/WSL2 and the files where being passed through to the VM from Windows over 9P. Whatever the intention of this check, it is clearly causing issues in real world scenarios. If it was really desired to check if the had changed since it was opened/stat'd then it would require a different methodology and be a patch for another day. But as it stands this current check does more harm than good, so lets just remove it. With it removed we now get for the above test file recvfrom(22, "GET /tfile HTTP/1.1\r\nHost: local"..., 2048, 0, NULL, NULL) = 82 openat(AT_FDCWD, "/mnt/9p/tfile", O_RDONLY|O_NONBLOCK) = 23 newfstatat(23, "", {st_mode=S_IFREG|0644, st_size=149922, ...}, AT_EMPTY_PATH) = 0 mmap(NULL, 135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f367817b000 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 131072, 0) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 18850, 61440) = 18850 writev(22, [{iov_base="HTTP/1.1 200 OK\r\nLast-Modified: "..., iov_len=171}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=18850}], 3) = 80461 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 69632, 80290) = 61440 pread64(23, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., 8192, 141730) = 8192 close(23) = 0 writev(22, [{iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=61440}, {iov_base="\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"..., iov_len=8192}], 2) = 69632 So we can see we do two pread(2)s's and a writev(2), then another two pread(2)s and another writev(2) and all the file data has been read and sent to the client. Reported-by: tonychuuy <https://github.com/tonychuuy> Link: <https://en.wikipedia.org/wiki/9P_(protocol)> Fixes: 08a8d15 ("Basic support for serving static files.") Closes: nginx#1064 Reviewed-by: Zhidao Hong <z.hong@f5.com> Reviewed-by: Andrei Zeliankou <zelenkov@nginx.com> Signed-off-by: Andrew Clayton <a.clayton@nginx.com>
I always get the following error:
This file size is 147kb, but if I try to load a css in the same directory with size of 1kb, it works fine.
My config file:
The text was updated successfully, but these errors were encountered: