nsresult nsBaseChannel::PushStreamConverter(const char *fromType, const char *toType, PRBool invalidatesContentLength, nsIStreamListener **result) { NS_ASSERTION(mListener, "no listener"); nsresult rv; nsCOMPtr<nsIStreamConverterService> scs = do_GetService(NS_STREAMCONVERTERSERVICE_CONTRACTID, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIStreamListener> converter; rv = scs->AsyncConvertData(fromType, toType, mListener, mListenerContext, getter_AddRefs(converter)); if (NS_SUCCEEDED(rv)) { mListener = converter; if (invalidatesContentLength) SetContentLength64(-1); if (result) { *result = nsnull; converter.swap(*result); } } return rv; }
nsresult nsInputStreamChannel::OpenContentStream(bool async, nsIInputStream **result, nsIChannel** channel) { NS_ENSURE_TRUE(mContentStream, NS_ERROR_NOT_INITIALIZED); // If content length is unknown, then we must guess. In this case, we assume // the stream can tell us. If the stream is a pipe, then this will not work. PRInt64 len = ContentLength64(); if (len < 0) { PRUint32 avail; nsresult rv = mContentStream->Available(&avail); if (rv == NS_BASE_STREAM_CLOSED) { // This just means there's nothing in the stream avail = 0; } else if (NS_FAILED(rv)) { return rv; } SetContentLength64(avail); } EnableSynthesizedProgressEvents(true); NS_ADDREF(*result = mContentStream); return NS_OK; }
nsresult nsDataChannel::OpenContentStream(PRBool async, nsIInputStream **result, nsIChannel** channel) { NS_ENSURE_TRUE(URI(), NS_ERROR_NOT_INITIALIZED); nsresult rv; nsCAutoString spec; rv = URI()->GetAsciiSpec(spec); if (NS_FAILED(rv)) return rv; nsCString contentType, contentCharset, dataBuffer; PRBool lBase64; rv = nsDataHandler::ParseURI(spec, contentType, contentCharset, lBase64, dataBuffer); NS_UnescapeURL(dataBuffer); if (lBase64) { // Don't allow spaces in base64-encoded content. This is only // relevant for escaped spaces; other spaces are stripped in // NewURI. dataBuffer.StripWhitespace(); } nsCOMPtr<nsIInputStream> bufInStream; nsCOMPtr<nsIOutputStream> bufOutStream; // create an unbounded pipe. rv = NS_NewPipe(getter_AddRefs(bufInStream), getter_AddRefs(bufOutStream), nsIOService::gDefaultSegmentSize, PR_UINT32_MAX, async, PR_TRUE); if (NS_FAILED(rv)) return rv; PRUint32 contentLen; if (lBase64) { const PRUint32 dataLen = dataBuffer.Length(); PRInt32 resultLen = 0; if (dataLen >= 1 && dataBuffer[dataLen-1] == '=') { if (dataLen >= 2 && dataBuffer[dataLen-2] == '=') resultLen = dataLen-2; else resultLen = dataLen-1; } else { resultLen = dataLen; } resultLen = ((resultLen * 3) / 4); // XXX PL_Base64Decode will return a null pointer for decoding // errors. Since those are more likely than out-of-memory, // should we return NS_ERROR_MALFORMED_URI instead? char * decodedData = PL_Base64Decode(dataBuffer.get(), dataLen, nsnull); if (!decodedData) { return NS_ERROR_OUT_OF_MEMORY; } rv = bufOutStream->Write(decodedData, resultLen, &contentLen); PR_Free(decodedData); } else { rv = bufOutStream->Write(dataBuffer.get(), dataBuffer.Length(), &contentLen); } if (NS_FAILED(rv)) return rv; SetContentType(contentType); SetContentCharset(contentCharset); SetContentLength64(contentLen); NS_ADDREF(*result = bufInStream); return NS_OK; }
NS_IMETHODIMP nsBaseChannel::SetContentLength(PRInt32 aContentLength) { SetContentLength64(aContentLength); return NS_OK; }
nsresult nsFileChannel::OpenContentStream(bool async, nsIInputStream **result, nsIChannel** channel) { // NOTE: the resulting file is a clone, so it is safe to pass it to the // file input stream which will be read on a background thread. nsCOMPtr<nsIFile> file; nsresult rv = GetFile(getter_AddRefs(file)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIFileProtocolHandler> fileHandler; rv = NS_GetFileProtocolHandler(getter_AddRefs(fileHandler)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIURI> newURI; rv = fileHandler->ReadURLFile(file, getter_AddRefs(newURI)); if (NS_SUCCEEDED(rv)) { nsCOMPtr<nsIChannel> newChannel; rv = NS_NewChannel(getter_AddRefs(newChannel), newURI); if (NS_FAILED(rv)) return rv; *result = nullptr; newChannel.forget(channel); return NS_OK; } nsCOMPtr<nsIInputStream> stream; if (mUploadStream) { // Pass back a nsFileUploadContentStream instance that knows how to perform // the file copy when "read" (the resulting stream in this case does not // actually return any data). nsCOMPtr<nsIOutputStream> fileStream; rv = NS_NewLocalFileOutputStream(getter_AddRefs(fileStream), file, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, PR_IRUSR | PR_IWUSR); if (NS_FAILED(rv)) return rv; nsFileUploadContentStream *uploadStream = new nsFileUploadContentStream(async, fileStream, mUploadStream, mUploadLength, this); if (!uploadStream || !uploadStream->IsInitialized()) { delete uploadStream; return NS_ERROR_OUT_OF_MEMORY; } stream = uploadStream; SetContentLength64(0); // Since there isn't any content to speak of we just set the content-type // to something other than "unknown" to avoid triggering the content-type // sniffer code in nsBaseChannel. // However, don't override explicitly set types. if (!HasContentTypeHint()) SetContentType(NS_LITERAL_CSTRING(APPLICATION_OCTET_STREAM)); } else { nsCAutoString contentType; rv = MakeFileInputStream(file, stream, contentType); if (NS_FAILED(rv)) return rv; EnableSynthesizedProgressEvents(true); // fixup content length and type if (ContentLength64() < 0) { PRInt64 size; rv = file->GetFileSize(&size); if (NS_FAILED(rv)) return rv; SetContentLength64(size); } if (!contentType.IsEmpty()) SetContentType(contentType); } *result = nullptr; stream.swap(*result); return NS_OK; }