I would like to add three “parts” to NSInputStream: NSString, exit from another stream, and then another NSString. The idea is this:
The first and last NSStrings represent the beginning and end of the SOAP request, while exiting the stream is the result of loading a very large file and encoding it as Base64 strings. So in the end, I will have the last NSInputStream containing the entire SOAP request as follows:
<soap start> <Base64 encoded data> <soap end>
The reason I want the whole request to be contained in NSInputStream is twofold:
- I do not need to load a very large data file into memory
I think this is the only way to ensure that the final request is sent to HTTP 1.1 hosts (which I need, because otherwise, if the request becomes too large, the server will not accept it). So, I know this does:
NSInputStream *dataStream = ....; [request setHTTPBodyStream:dataStream];
ensures that the request will be sent as fragments of HTTP 1.1, and not as one huge raw SOAP request.
So, I wonder how this can be achieved - namely, how can I “insert” things into NSInputStream? Can this be done? Is there an alternative way?
Just for reference, in Java this can be done as follows
Vector<InputStream> streamVec = new Vector<InputStream>(); BufferedInputStream fStream = new BufferedInputStream(fileData.getInputStream()); Base64InputStream b64stream = new Base64InputStream(fStream, true); String[] SOAPBody = GenerateSOAPBody(fileInfo).split("CUT_HERE"); streamVec.add(new ByteArrayInputStream(SOAPBody[0].getBytes())); streamVec.add(b64stream); streamVec.add(new ByteArrayInputStream(SOAPBody[1].getBytes())); SequenceInputStream seqStream = new SequenceInputStream(streamVec.elements());
because Java has these objects, but NSStreams in objective-c look like very low-level objects and it’s very difficult to work with them.
Note. I completely rewrote the original question, as I asked it 2 days ago, since I think the new editing more clearly explains what the problem is. I hope this helps him to better understand and possibly respond.
UPDATE 2
Here's what I managed to achieve: instead of trying to insert into the stream, I use a temporary file to write <soap start> first, then I set up the input stream to read from the file in pieces, encoded each piece as a Base64 string and wrote it to the same temp file, finally, when my thread closes, I write a <soap ends> temporary file. Then, I installed another input stream with the contents of this file, which I pass to NSMutableURLRequest:
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; ... NSInputStream *dataStream = [NSInputStream inputStreamWithFileAtPath:_tempFilePath]; [request setHTTPBodyStream:dataStream];
This ensures that HTTP 1.1 file contents are transferred. After the connection is complete, delete the temporary file.
This seems to work fine, but of course it is annoying work. I do not want to write to a temporary file when all this could be processed by threads (ideally). If anyone else has the best deals let me know :)
UPDATE 3
OK, another update is ok. Although my writing to a file seems to work, now I am facing an unexpected problem when some of my requests are not uploaded to the server. In particular, everything goes according to plan, I read the contents of the temporary file in the stream and set the HTTP body of my request as this stream, and it starts to send HTTP fragments as I want, but for some the reason some packets are dropped and the final request - this is my hunch - gets the wrong form and thus fails. I think that the problem with packaged packages is random, because I observe it with larger requests - that is, the problem just has a better chance of appearing - while my smaller requests usually go through a fine. This, of course, is a separate question from the original in this question. If someone has a good idea what could be causing this, I asked about the problem here: Packets dropped during a chunked HTTP 1.1 request sent by NSURLConnection