The Inbox: WebClient-Core-ct.125.mcz

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

The Inbox: WebClient-Core-ct.125.mcz

commits-2
Christoph Thiede uploaded a new version of WebClient-Core to project The Inbox:
http://source.squeak.org/inbox/WebClient-Core-ct.125.mcz

==================== Summary ====================

Name: WebClient-Core-ct.125
Author: ct
Time: 8 September 2020, 10:09:01.217336 am
UUID: b5a5321e-904d-ca40-aa6a-8ae3236fe629
Ancestors: WebClient-Core-ct.124

Adds UTF-8 conversion to multipart/form-data encoding & decoding in WebUtils. Also includes overall refactoring of the relevant methods. Last but not least, makes the filename parameter optional as specified in RFC7578 Sec. 4.2.

NOTE that this is a breaking change for any users of the multipart/form-data protocol provided by the WebClient package! If you manually converted (file)names or plain-text fields to UTF-8 via #squeakToUtf8 before passing them to the WebClient, you should stop doing so now. Vice versa, as a user of WebRequest >> #fields or #multipartFields, you should no longer call #utf8ToSqueak on the output.

For more information, please refer to [2]. Thanks to Levente (ul) for the help!

Depends indeed on WebClient-Core-ct.124.

[1] https://tools.ietf.org/html/rfc7578#section-4.2
[2] http://forum.world.st/Are-we-missing-some-string-encoding-in-SqueakSSL-WebClient-td5121341.html

=============== Diff against WebClient-Core-ct.124 ===============

Item was changed:
  ----- Method: WebUtils class>>decodeMultipartForm:boundary:do: (in category 'decoding') -----
  decodeMultipartForm: aStream boundary: boundary do: aBlock
  "Parse the contents of a multipart/form-data submission.
+
+ Evaluate aBlock with three parts: The headers, the (parsed) form-data arguments and the (undecoded) contents of the part. The sender is expected to take care of other issues such as content-transfer-encoding and similar headers."
 
- Evaluate aBlock with three parts: The headers, the (parsed) form-data
- arguments and the (undecoded) contents of the part. The sender is
- expected to take care of other issues such as content-transfer-encoding
- and similar headers."
-
  | skip headers content disposition index params |
  aStream upToAll: '--', boundary.
+ [aStream atEnd or: [(skip := aStream next: 2) = '--']] whileFalse: [
+ self assert: skip = String crlf description: 'Error decoding multipart/form-data fields'.
+
+ headers := Dictionary newFrom: (WebUtils readHeadersFrom: aStream).
- [aStream atEnd or:[(skip := aStream next: 2) = '--']] whileFalse:[
- skip = String crlf ifFalse:[self error: 'Error decoding multipart/form-data fields'].
- headers := Dictionary new.
- (WebUtils readHeadersFrom: aStream) do:[:hdr| headers add: hdr].
- content := aStream upToAll: String crlf, '--', boundary.
  params := Dictionary new.
+ content := aStream upToAll: String crlf, '--', boundary.
+
+ disposition := (headers at: 'content-disposition' ifAbsent: ['']) utf8ToSqueak.
+ self flag: #todo. "Support content-type and charset as described in RFC7578."
+ #(name filename) do: [:arg |
+ | len |
- disposition := headers at: 'content-disposition' ifAbsent:[''].
- #(name filename) do:[:arg| | len val |
  len := arg size + 2.
+ index := disposition findString: arg, '='.
+ index > 0 ifTrue: [
+ params at: arg put: (disposition
+ copyFrom: index + len
+ to: (disposition indexOf: $" startingAt: index + len) - 1) utf8ToSqueak]].
+ aBlock value: headers value: params value: content].!
- index := disposition findString: arg,'='.
- index > 0 ifTrue:[
- val := disposition copyFrom: index + len to: (disposition indexOf: $" startingAt: index+len) - 1.
- params at: arg put: val.
- ].
- ].
- aBlock value: headers value: params value: content.
- ].!

Item was changed:
  ----- Method: WebUtils class>>encodeMultipartForm:boundary: (in category 'decoding') -----
  encodeMultipartForm: fieldMap boundary: boundary
+ "Encode the fieldMap as multipart/form-data.
+
+ The fieldMap may contain MIMEDocument instances to indicate the presence of a file to upload to the server. If the MIMEDocument is present, its content type and file name will be used for the upload.
+
+ The fieldMap can be EITHER an array of associations OR a Dictionary of key value pairs (the former is useful for providing multiple fields and/or specifying the order of fields)."
- "Encodes the fieldMap as multipart/form-data.
 
+ ^ String streamContents: [:stream |
+ (fieldMap as: OrderedDictionary) keysAndValuesDo: [:fieldName :fieldValue |
+ | fieldContent |
- The fieldMap may contain MIMEDocument instances to indicate the presence
- of a file to upload to the server. If the MIMEDocument is present, its
- content type and file name will be used for the upload.
-
- The fieldMap can be EITHER an array of associations OR a Dictionary of
- key value pairs (the former is useful for providing multiple fields and/or
- specifying the order of fields)."
-
- ^String streamContents:[:stream|
- (fieldMap as: Dictionary) keysAndValuesDo:[:fieldName :fieldValue | | fieldContent |
  "Write multipart boundary and common headers"
  stream nextPutAll: '--', boundary; crlf.
+ stream nextPutAll: 'Content-Disposition: form-data; name="'
+ , fieldName squeakToUtf8
+ , '"'.
+ self flag: #todo. "Support Content-Type and charset as described in RFC7578."
+
+ "Write field content - either a file or a string"
+ fieldContent := (fieldValue isKindOf: MIMEDocument)
+ ifTrue: [
+ fieldValue url ifNotNil: [:url |
+ stream nextPutAll: '; filename="', url pathForFile squeakToUtf8, '"'].
+ stream crlf.
+ stream
+ nextPutAll: 'Content-Type: ';
+ nextPutAll: fieldValue contentType squeakToUtf8.
+ (fieldValue content ifNil: [
+ (FileStream readOnlyFileNamed: fieldValue url pathForFile) contentsOfEntireFile]) asString]
+ ifFalse: [fieldValue asString squeakToUtf8].
- stream nextPutAll: 'Content-Disposition: form-data; name="', fieldName, '"'.
- "Figure out if this is a file upload"
- (fieldValue isKindOf: MIMEDocument) ifTrue:[
- stream nextPutAll: '; filename="', fieldValue url pathForFile, '"'; crlf.
- stream nextPutAll: 'Content-Type: ', fieldValue contentType.
- fieldContent := (fieldValue content ifNil:[
- (FileStream readOnlyFileNamed: fieldValue url pathForFile) contentsOfEntireFile.
- ]) asString.
- ] ifFalse: [fieldContent := fieldValue].
  stream crlf; crlf.
+ stream nextPutAll: fieldContent.
+
+ stream crlf].
+ stream nextPutAll: '--', boundary, '--', String crlf]!
- stream nextPutAll: fieldContent asString.
- stream crlf.
- ].
- stream nextPutAll: '--', boundary, '--', String crlf.
- ].
- !