public async Task ReadAndExecuteRequestAsync() { if (MultipartPartParser.IsEndPart) { HandleMultipartReadError("End part detected after reading Headers. No more parts detected."); } if (!MultipartPartParser.IsEndPart && !string.IsNullOrWhiteSpace(MultipartPartParser.Filename)) { await ExecuteFunctionAsync(MultipartPartParser); // move the stream foward until we get to the next part MultipartPartParser = MultipartPartParser.ReadUntilNextPart(); if (MultipartPartParser != null) { HandleMultipartReadError("Only one part is supported for multi-part."); } return; } HandleMultipartReadError("Error reading multi-part"); }
/// <summary> /// Reads the stream, if this part has completed the nextpart is returned /// </summary> /// <param name="buffer"></param> /// <param name="offset"></param> /// <param name="count"></param> /// <param name="nextpart"></param> /// <returns></returns> public int ReadForNextPart(byte[] buffer, int offset, int count, out MultipartPartParser nextpart) { // If we have found our next part we have already finsihed this part and should stop here if (NextPart != null || IsEndPart) { nextpart = NextPart; return(0); } // the search buffer is the place where we will scan for part bounderies. We need it to be just // a bit bigger than than the size requested, to ensure we dont accidnetly send part of a boundary // without realising it byte[] searchBuffer = new byte[count + BoundaryWithNewLinePrepend.Length]; int bytesReadThisCall = 0; // first read from our local buffer int bytesToReadFromLocalBuffer = Math.Min((int)LocalBuffer.Length, searchBuffer.Length); if (bytesToReadFromLocalBuffer > 0) { bytesReadThisCall += LocalBuffer.Read(searchBuffer, bytesReadThisCall, bytesToReadFromLocalBuffer); } // if we could not fill our search buffer with our local buffer then read from the multipart stream int bytesToReadFromStream = searchBuffer.Length - bytesReadThisCall; bytesToReadFromStream = Math.Min(bytesToReadFromStream, (int)MultipartStream.Length - (int)MultipartStream.Position); if (bytesToReadFromStream > 0) { bytesReadThisCall += MultipartStream.Read(searchBuffer, bytesReadThisCall, bytesToReadFromStream); } // the number of bytes returned will be one of three cases // 1. There is still plenty to return so we will return the 'count' they asked for // 2. We have emptied the stream, we will return the bytes read // 3. We have run into a new boundary, we will return the bytes up to the boundary end int bytesReturned; bool isEndOfPart = SearchBytePattern(BoundaryWithNewLinePrepend, searchBuffer, out bytesReturned); // we can only return the parts we know for sure are not part of the next boundary // which is the bytes we read minus the boundary length. This will also ensure we // get back to the count we were originally asked for. We also need to make sure we // return 0 bytes if we can not gaurentee there are no boundaries parts in what we // did manage to read if (!isEndOfPart) { bytesReturned = Math.Max(0, bytesReadThisCall - BoundaryWithNewLinePrepend.Length); } Buffer.BlockCopy(searchBuffer, 0, buffer, offset, bytesReturned); // We need to handle the bytes that did not get returned by putting them back into // the local buffer int bytesNotReturned = bytesReadThisCall - bytesReturned; ReinsertIntoLocalBuffer(searchBuffer, bytesReturned, bytesNotReturned); nextpart = null; if (isEndOfPart) { // the boundary we were looking for had a newline appended to it // we dont want to send the newline to the next part so we will skip LocalBuffer.Position += NewLine.Length; NextPart = new MultipartPartParser(MultipartStream, Encoding, _log, LocalBuffer); // The next part may actually just the be end indicator, if thats the case // we will null it and not return it if (NextPart.IsEndPart) { NextPart = null; } nextpart = NextPart; } return(bytesReturned); }
protected MultipartReader(Stream stream, IServiceLogRepository log) { MultipartPartParser = new MultipartPartParser(stream, log); _log = log; }