-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
128 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
using GLib; | ||
using Soup; | ||
|
||
namespace VSGI { | ||
|
||
/** | ||
* It provides similar APIs to {@link Soup.MultipartInputStream}. | ||
* | ||
* @since 0.3 | ||
*/ | ||
public class MultipartInputStream : FilterInputStream { | ||
|
||
public MessageHeaders headers { construct; get; } | ||
|
||
public MultipartInputStream (MessageHeaders headers, InputStream base_stream) { | ||
Object (headers: headers, base_stream: base_stream); | ||
} | ||
|
||
/** | ||
* Obtain the stream over the next part of that multipart message. | ||
* | ||
* @return a stream over the next part of null if none's available | ||
*/ | ||
public InputStream? next_part (out MessageHeaders part_headers, Cancellable? cancellable = null) throws IOError { | ||
HashTable<string, string> @params; | ||
headers.get_content_type (out @params); | ||
|
||
var boundary = @params["boundary"]; | ||
|
||
assert (@params.contains ("boundary")); | ||
|
||
var line_reader = new DataInputStream (base_stream); | ||
|
||
line_reader.newline_type = DataStreamNewlineType.CR_LF; | ||
|
||
// read until the next boundary | ||
do { | ||
var line = line_reader.read_line (null, cancellable); | ||
|
||
if (line == null) | ||
break; // end of input | ||
|
||
if (line == "--" + boundary) { | ||
// consume current headers | ||
var headers = new StringBuilder (); | ||
|
||
do { | ||
var header_line = line_reader.read_line (null, cancellable); | ||
|
||
if (header_line == "") | ||
break; // empty line preceeding the body | ||
|
||
if (header_line == null) | ||
return null; // end of input..? | ||
|
||
headers.append (header_line + "\r\n"); | ||
} while (true); | ||
|
||
headers_parse (headers.str, (int) headers.len, part_headers); | ||
|
||
return base_stream; | ||
} | ||
|
||
if (line == "--" + boundary + "--") | ||
return null; // end of multipart message (eiplogue follows...) | ||
} while (true); | ||
|
||
return null; // end of input | ||
} | ||
|
||
public override ssize_t read (uint8[] buffer, Cancellable? cancellable = null) throws IOError { | ||
return base_stream.read (buffer, cancellable); | ||
} | ||
|
||
public override bool close (Cancellable? cancellable = null) throws IOError { | ||
return base_stream.close (cancellable); | ||
} | ||
} | ||
|
||
/** | ||
* | ||
* @since 0.3 | ||
*/ | ||
public class MultipartOutputStream : FilterOutputStream { | ||
|
||
public MessageHeaders headers { construct; get; } | ||
|
||
public MultipartOutputStream (MessageHeaders headers, OutputStream base_stream) { | ||
Object (headers: headers, base_stream: base_stream); | ||
} | ||
|
||
/** | ||
* Create a new part in this multipart message. | ||
*/ | ||
public OutputStream new_part (MessageHeaders part_headers) throws IOError { | ||
HashTable<string, string> @params; | ||
headers.get_content_type (out @params); | ||
|
||
var boundary = @params["boundary"]; | ||
var writer = new DataOutputStream (base_stream); | ||
|
||
part_headers.foreach ((k, v) => { | ||
writer.put_string ("%s: %s\r\n".printf (k, v)); | ||
}); | ||
|
||
writer.put_string ("\r\n"); | ||
|
||
return base_stream; | ||
} | ||
|
||
public override ssize_t write (uint8[] buffer, Cancellable? cancellable = null) throws IOError { | ||
return base_stream.write (buffer, cancellable); | ||
} | ||
|
||
/** | ||
* Append the final enclosing boundary and close the base stream. | ||
*/ | ||
public override bool close (Cancellable? cancellable = null) throws IOError { | ||
HashTable<string, string> @params; | ||
headers.get_content_type (out @params); | ||
|
||
var boundary = @params["boundary"]; | ||
var writer = new DataOutputStream (base_stream); | ||
|
||
return writer.put_string ("--" + boundary + "--\r\n", cancellable) && base_stream.close (cancellable); | ||
} | ||
} | ||
} |