The spec says:
The server SHOULD send PUSH_PROMISE (Section 6.6) frames prior to
sending any frames that reference the promised responses. This avoids
a race where clients issue requests prior to receiving any
PUSH_PROMISE frames.
For example, if the server receives a request for a document
containing embedded links to multiple image files and the server
chooses to push those additional images to the client, sending
PUSH_PROMISE frames before the DATA frames that contain the image
links ensures that the client is able to see that a resource will be
pushed before discovering embedded links.
In the example given, I assume it would be okay for the server to send the image data before or after the "document containing embedded links to multiple image files".
Are all of these allowed?
Series A
client requests document
server sends PUSH_PROMISE of images
server sends document
server sends images
Series B
client requests document
server sends PUSH_PROMISE of images
server sends images
server sends document
Series C
client requests document
server sends PUSH_PROMISE of images
server sends images/document concurrently, i.e. frames are interspersed
(In all cases, When the client makes a request for the images, it blocks on them being received locally on the promised stream id.)
All three options are viable for a server.
For example, Jetty implements option C.
However, I would not make any assumption on the behavior of the client, assuming that it will wait because it received the PUSH_PROMISE.
For example, if the client urgently needs one of the resources that have been promised, it may cancel the pushed resource and issue a request for that resource with a high priority.
Related
I was reading this post and it was saying there could be an issue with deadlocks if you send too much data without receiving. Is it bad to send the whole file over in a single send call? If so then what is the correct way of doing it?
I have tried sending large files using single send calls and wait until i receive it on the other end also. Sometimes the connection hangs. Maybe it could be a deadlock or improper use?
TL;DR: there are no problems doing large send with TCP itself, but there are problems in the specific example you cite.
As for TCP in general:
Using a large sent is not a problem. The network layer of your OS will take care of everything. All you need to do is make sure is that the data gets actually transmitted to the OS, i.e. check the result of sent and retry with everything not already covered by the previous sent. sent will just block your application if it currently cannot send (write buffer full). But this requires that the server will actually receive the data. If not then the server side read buffer will fill up which causes the TCP window to decrease and ultimately the send to stop until the server is actually reading the previously sent data.
As for your specific linked example:
In your specific linked example there is an application protocol on top of TCP which changes the semantics. It is not plain TCP anymore where the client could send without receiving, but it actually requires the client to also receive data. To cite the relevant part:
The server sends one byte for every 3 bytes received.
Thus, if you send a large amount of data, then the server will send a matching amount of data back - size being one third of what you have sent. This sender emitted data will be put in the read buffer of your socket. If you don't recv then this read buffer will get full. This will cause the client network stack to signal to the server a TCP window of 0 and the server will stop sending data.
If the TCP window is 0 then the server cannot send anymore data on this socket. This means that the server will be stuck in send. If the server cannot handle recv and send on the same socket in parallel, then the server will be stuck in send and not call recv anymore - which fill fill up the server side read buffer and ultimately cause the TCP window for data from client to server to be 0 too.
In this situation both client and server will be stuck in send since nobody is receiving the data sent by the other and thus the TCP window stays 0 in both directions - deadlock.
I am implementing a SMB protocol decoder.
I don’t understand how, when reading a file/named pipe, the client understands that the response is associated with one of many open files/named pipes.
The client sends the file descriptor (file id), but the server does not send it back in the response. The server does not send any data linking the request to the response.
You can verify this by reading about SMB operations such as: SMB_COM_READ, TRANS_READ_NMPIPE in the MS-CIFS standard.
If there were several read requests or even several files/named pipes open, then how does the client understand which request the server responded to?
One can bind requests using a map using file_id as a key, while each request is added to the queue, and the decoding of each response is based on this queue.
(Binding requests) Each request will be placed in the map with the key file_id, and when subsequent requests to the file received, I can find out all the previous requests.
(Binding requests and responses) Also, each request is placed in a queue and an file_id is assigned to it, the file_ids of requests to one file are equal, when a response is received, the top element of the queue will be retrieved and an file_id will be obtained from it.
Problem
I am wondering how webpush protocol works? Does it keep some kind of connection open like WebSocket protocol? Or does it use mechanism similar to polling?
Tried
According to documentation WebPush uses HTTP 2.0 server push:
A simple protocol for the delivery of real-time events to user agents
is described. This scheme uses HTTP/2 server push.
Server push wikipedia:
HTTP/2 Server Push is not a notification mechanism from server to client. Instead, pushed resources are used by the client when it may have otherwise produced a request to get the resource anyway;
HTTP/2 server push example scenario:
Consider a website with three resources: index.html, styles.css and script.js. When a user, through their browser, connects to the home page of this website they automatically retrieve index.html. As the browser parses the HTML text in index.html, it finds instructions that will require styles.css and script.js. At that point, the browser will issue requests to get these other two files.
With HTTP/2 Push, the server can take the initiative by having rules that trigger content to be sent even before it is requested. In this example scenario, the server knows that anyone requesting index.html will need styles.css and script.js, so it can push them to the client immediately without waiting for the client to request them.
According to HTTP/2 server push itt seems that WebPush protocol should return some kind of notifications before they are requested by client. But I am no sure about it. So here is my question: How it exactly works underhood?
From what I understand, what multiplexing means is that the client just need to create one TCP connection with the server and it can send multiple requests at the same time without having to wait for the response of one request before continuing another. So if I send 3 request at the same time, there are also 3 response streams.
And for server push, the client sends one request to the server, the server then guesses that the client needs other resources (also called promises) other than the one it requested, so it sends push promise streams hinting the client with the URL of the additional resources. The client may choose to request those additional resources or not.
My questions are:
For any response sent from the server to the client, does it have to be a request initiated first? I mean, it I created a connection to
the server, I did not send any request. Could I be getting responses
from server via server push? In multiplexing, I get same number of
responses for same number of requests. In server push, I can get
multiple responses for one request. So does there always have to be a
request first?
In server push, when a promise stream is sent by the server to the client containing the URL of the additional resources, does that mean
the server will only push the additional resources only when the
client accepts the promises?
[the server] sends push promise streams hinting the client with the URL of the additional resources. The client may choose to request those additional resources or not.
This is not correct. When the server sends to the client a PUSH_PROMISE, the server will then send the resource content associated to that pushed resource.
The only thing that the client can do is to reset the pushed stream via a RST_STREAM frame, but it may well be that the whole pushed resource is already in-flight so resetting the pushed stream has no effect: the client will receive the pushed resource bytes and may discard them if not interested.
To answer your specific questions:
Yes, a response from the server is always client-initiated. If a client does not send any request to the server, the server cannot push to the client. Even in the case of server push, the client always initiated a stream by making a request, and server pushes are always associated to that "parent" request.
The PUSH_PROMISE frame is an indication from the server to the client of what resource the server is about to push. The client does not "accept" pushes, the server forces them to the client. The only thing the client can do is to reset the stream associated with the pushed resource; as I said, the server may have already pushed the whole resource by the time it receives the RST_STREAM frame from the client.
I have an intranet based CRM application developed in CodeIgniter 2.1 where the application is running on a local Apache server and around 20 clients are accessing it over LAN. This is to be connected to a call center setup where the call center application (running on a separate server) will do a HTTP post with caller's number as well as terminal number of the agent where the call is arriving to a URL of my Codeigniter application. I am using this data to populate a database table of call records.
Now from the terminal number (each terminal has static IP, and a session in Codeigniter is linked to IP as well) I can find out which user (login session) of my application is about to receive the call. I want to find a way out how I can send data from server side (it will be regarding the call like the number who is calling, past call records etc.) to that specific user's browser via AJAX or something similar? The agent's browser needs to display this information sent from server.
Periodic polling from browser by jquery etc. is not possible as the data needs to be updated almost instantaneously and rapid polling up to this extent will lead to high CPU usage at client end as well as extra load on network.
P.S.: I only want to know how to modify the browser data from server end.
In AJAX, asynchronous request/response doesn't involve polling; there's just an open TCP connection and non-blocking I/O. The client makes a request but returns immediately; when the server sends the response, the client is notified. So you can achieve what you want with AJAX's XMLHttpRequest without polling[1]. All you need is a url from which to serve your notifications. You could have one request thread and a general dispatch method, or different urls and different threads for each, depending on how you needed to scale.
[1] Well, to be honest, with very little polling. You'd really need to establish what the session/global timeout was and reissue requests within that time limit.