thank you for reading my question. I have read numerous documents about HTTP/2 and tried to understand most important concepts for constructing a APNs server-side API in Java.
So far, I have a working code for creating Payload and initiating ssl handshake with APNs.
I am stuck with figuring out a way to send Push Notification to APNs, specifically sending a HTTP/2 POST request to the Apple server.
APNs requires the use of HPACK (header compression for HTTP/2), which
prevents repeated header keys and values. APNs maintains a small
dynamic table for HPACK. To help avoid filling up the APNs HPACK table
and necessitating the discarding of table data, encode headers in the
following way—especially when sending a large number of streams:
If I have understood correctly, I need to use Huffman Encoding for the header compression. If I am wrong on this, please correct me.
The :path value should be encoded as a literal header field without
indexing
The authorization request header, if present, should be encoded as a
literal header field without indexing
I read RFC 7541 for this, but have no idea what they are talking about. Please note that I am trying to understand the system and requirements to gain knowledge through this post, not just answers to the specific questions.
The appropriate encoding to employ for the apns-id, apns-expiration,
and apns-collapse-id request headers differs depending on whether it
is part of the initial or a subsequent POST operation, as follows:
The first time you send these headers, encode them with incremental
indexing to allow the header names to be added to the dynamic table
Subsequent times you send these headers, encode them as literal header
fields without indexing
What do they mean when they say, "encode them with incremental indexing to allow the header names to be added to the dynamic table" and "Subsequent times you send these headers, encode them as literal header fields without indexing" afterwards. I guess understanding one of two literal header fields with/out indexing will help me comprehend this better.
Thank you again for reading the question and please help me with this!!
I think you will be better off using a Java library that does HTTP/2 for you.
The Jetty HttpClient (disclaimer, I'm the maintainer) does exactly that, see here.
If instead you want to implement HPACK because you want to have fun, then you have to take your time and read carefully RFC 7541.
As an starting point for implementing it, you can read the many Java implementations of HPACK out there, from Jetty's to Netty's, Undertow's, etc.
All the questions you are asking (e.g. "what is a 'literal header field without indexing') are detailed in the RFC in their own sections.
Very coarsely, HPACK defines a mapping table that maps numbers to strings.
Both peer maintain this table in sync, so that the two tables always contain the same data (at rest).
When one peer sends a HPACK block, it sends the numbers, so that the receiving peer can use the numbers to access the HPACK table to obtain the strings.
For new/custom headers (think cookies), the sending peer sends the number and the string, so that the receiving peer can update its HPACK table. For the first time there is no compression, but the second time that the same header is sent, the sending peer just sends the number, since it knows that the other peer will have the string mapped already, and this gives good compression of HTTP headers.
Related
I have a curl that will make a post request. I have tried it in the command line and it works fine, so I know all my values that I should use. However, I am quite lost when it comes to translating this into Java.
I need to send form data and header data. The header is my authorization, and the form data contains both Strings and Dates, but again, the problem is that I don't know how to translate this into Java.
I have tried using URIBuilder and adding my form data with the addParameter, but it seems as if that one can only accept Strings and does not have any function for setting header information?
So I tried using HttpPost instead where I found the addHeader function that enables me to add my header data, but I did not find any function for adding the form data with this option.
I would be thankful if anyone could help me in any way possible.
Jersey 2.4.1 gives us the ability to enable fixed length streaming. This is very useful when uploading large files. The new client property for enabling this is: HTTP_URL_CONNECTOR_FIX_LENGTH_STREAMING.
By default, when doing uploads, the whole entity content is buffered by the connector before the bytes are sent to their destination. This means that the client will likely run out of memory when uploading large files. Enabling fixed length streaming solves this problem.
Unfortunately this property is not honored when the content-length header is not specified (or is set to 0) in the request. My question is why? What problem are the Jersey runtimes trying to prevent by putting this restriction? Is the content length information necessary to stream the data?
Thanks,
Habib
Whether fixed length streaming is actived or not, the client should set the header anyway. With fixed length you know the size without the need of buffering the content but that only makes sense if you actually set the header. The server doesn't care if the client buffered the content to determine the length or not.
In HTTP, [the Content-Length field] SHOULD be sent whenever the message's length can be determined prior to being transferred, unless this is prohibited by the rules in section 4.4.
RFC 2616, section 14.13 Content-Length
Without setting the length header, the client could start streaming indefinitely, without a buffer. I guess this it what Jersey tries to prevent, because then the server wouldn't know when the content ends (exept some cases listed in
RFC 2616, section 4.4 Message Length).
I forward upload requests I receive from clients to an another endpoint. I do not control the presence of the content length header in the requests I receive, and therefore may not always have a content length header to send to the end point.
That said, I can see that we need to protect against the malicious case you mention above, although I initially thought this would be the backend's responsibility.
Thanks for the clarification.
I am using URL class in java and I want to read bytes through Input Stream from a specific byte location in the stream instead of using skip() function which takes a lot of time to get to that specific location.
I suppose it is not possible and here is why: when you send GET request, remote server does not know that you are interested in bytes from 100 till 200 - he sends you full document/file. So you need to read them, but don't need to handle them - that is why skip is slow.
But: I am sure that you can tell server (some of them support it, some - don't) that you want 100+ bytes of file.
Also: see this to get in-depth knowledge about skip mechanics: How does the skip() method in InputStream work?
The nature of streams mean you will need to read through all the data to get to the specific place you want to start from. You will not get faster than skip() unfortunately.
The simple answer is that you can't.
If you perform a GET that requests the entire file, you will have to use skip() to get to the part that you want. (And in fact, the slowness is most likely because the server has to send all of the data that is being skipped to the client. That is how TCP/IP works ...)
However, there is a possible alternative. The HTTP 1.1 specification supports partial fetching documents using the Range header. If your server supports this, then you can request the server to send you just the range of the document that you are interested in. However, you may need to deal with the case where the server ignores the Range header and sends the entire document anyway.
Can someone explain to me what is actually the need to Url-encode
data sent in the body part of http requests when using
content-type: application/x-www-form-urlencoded
thanks
By "the need", do you mean "the purpose"?
If you're after the purple - it is simply there to tell the server what to expect: URL-encoded key=value pairs. It also allows the server to know what is not coming its way - the likes of multipart/form-data!
This allows the server to unambiguously know how to read incoming data.
The data is sent as one header (this is also why it has a size limit). As such, you definitely want to avoid stuff like: newlines, colons. In addition to this, you definitely want to escape = in data, so that it doesn't mess with the key=value structure. You also want to escape & for the same reason. URL-encoding does all that - so it only makes sense that whoever designed the HTTP protocol went for it!
There are multiple ways to send data to the server in a POST request; URL Encoded data is just one of several possible formats.
The client and server have to agree on the format of data in the POST body. URL Form encoded data is the easiest to use because of its universal support. Browsers support it natively. Every programming language allows you to read url encoded post parameters using a familiar syntax.
But of course, there is no need to use url form encoded. You can as easily send json or xml encoded POST body. As long as the client and server are in sync, you can even create a totally different encoding and use it.
I want to write an application in Java that will communicate with Google App Engine app written in Go by sending and receiving dynamic data. The data is not human readable (as in, not ASCII, Unicode or the like) and ranges from a couple bytes to about 1MB.
I am wondering if it is possible to send such data to and from GAE using Post method directly, or is it better to just encode it as a hex dump and transfer is at text (thusly increasing its size a couple times)?
Yes, this is possible, of course. Just like an HTTP response, an HTTP request can contain a payload of any sort (unless it's a GET or other method that doesn't permit a body); just set the content-type appropriately and send the data in the body of the HTTP request.
If people can POST 10mb photos to Facebook, then I don't see why you can't do that with your data :)