[squeak-dev] The Trunk: Network-ul.41.mcz
commits at source.squeak.org
commits at source.squeak.org
Thu Dec 3 03:18:02 UTC 2009
Levente Uzonyi uploaded a new version of Network to project The Trunk:
http://source.squeak.org/trunk/Network-ul.41.mcz
==================== Summary ====================
Name: Network-ul.41
Author: ul
Time: 2 December 2009, 6:11:43 am
UUID: 0598c060-af2b-ca4b-8fa3-09e0dd0162ae
Ancestors: Network-nice.40
- merged http://bugs.squeak.org/view.php?id=7291
=============== Diff against Network-nice.40 ===============
Item was changed:
----- Method: HTTPSocket class>>httpPost:args:user:passwd: (in category 'get the page') -----
httpPost: url args: args user: user passwd: passwd
+
+ | authorization result |
- | authorization |
authorization := (user , ':' , passwd) base64Encoded.
+ result := self
+ httpPostDocument: url args: args accept: '*/*'
+ request: 'Authorization: Basic ' , authorization , CrLf.
+ result isString ifFalse: [ ^result ].
+
+ authorization := self digestFor: result method: 'POST' url: url user: user password: passwd.
+ authorization ifNil: [ ^result ].
^self
httpPostDocument: url args: args accept: '*/*'
+ request: 'Authorization: Digest ' , authorization , CrLf.
+ !
- request: 'Authorization: Basic ' , authorization , CrLf!
Item was changed:
+ ----- Method: HTTPSocket class>>httpGetDocument:args:accept:request: (in category 'proxy settings') -----
- ----- Method: HTTPSocket class>>httpGetDocument:args:accept:request: (in category 'get the page') -----
httpGetDocument: url args: args accept: mimeType request: requestString
"Return the exact contents of a web object. Asks for the given MIME
type. If mimeType is nil, use 'text/html'. An extra requestString may be
submitted and must end with crlf. The parsed header is saved. Use a
proxy server if one has been registered. tk 7/23/97 17:12"
"Note: To fetch raw data, you can use the MIME type
'application/octet-stream'."
| serverName serverAddr port sock header length bare page list firstData
aStream index connectToHost connectToPort type newUrl |
Socket initializeNetwork.
bare := (url asLowercase beginsWith: 'http://')
ifTrue: [url copyFrom: 8 to: url size]
ifFalse: [url].
bare := bare copyUpTo: $#. "remove fragment, if specified"
serverName := bare copyUpTo: $/.
page := bare copyFrom: serverName size + 1 to: bare size.
(serverName includes: $:)
ifTrue: [ index := serverName indexOf: $:.
port := (serverName copyFrom: index+1 to: serverName size) asNumber.
serverName := serverName copyFrom: 1 to: index-1. ]
ifFalse: [ port := self defaultPort ].
page size = 0 ifTrue: [page := '/'].
"add arguments"
args ifNotNil: [page := page, (self argString: args) ].
(self shouldUseProxy: serverName)
ifFalse: [
connectToHost := serverName.
connectToPort := port ]
ifTrue: [
page := 'http://', serverName, ':', port printString, page. "put back
together"
connectToHost := self httpProxyServer.
connectToPort := self httpProxyPort].
serverAddr := NetNameResolver addressForName: connectToHost timeout: 20.
serverAddr ifNil: [
^ 'Could not resolve the server named: ', connectToHost].
3 timesRepeat: [
sock := HTTPSocket new.
sock connectTo: serverAddr port: connectToPort.
(sock waitForConnectionUntil: (self deadlineSecs: 30)) ifFalse: [
Socket deadServer: connectToHost. sock destroy.
^ 'Server ',connectToHost,' is not responding'].
"Transcript cr;show: url; cr.
Transcript show: page; cr."
sock sendCommand: 'GET ', page, ' HTTP/1.0', CrLf,
(mimeType ifNotNil: ['ACCEPT: ', mimeType, CrLf] ifNil: ['']),
'ACCEPT: text/html', CrLf, "Always accept plain text"
HTTPBlabEmail, "may be empty"
requestString, "extra user request. Authorization"
self userAgentString, CrLf,
'Host: ', serverName, ':', port printString, CrLf. "blank line
automatically added"
+ list := sock getResponseUpTo: CrLf, CrLf ignoring: String cr. "list = header, CrLf, CrLf,
- list := sock getResponseUpTo: CrLf, CrLf ignoring: (String with: CR). "list = header, CrLf, CrLf,
beginningOfData"
header := list at: 1.
"Transcript show: page; cr; show: header; cr."
firstData := list at: 3.
header isEmpty
ifTrue: [aStream := 'server aborted early']
ifFalse: [
"dig out some headers"
sock header: header.
length := sock getHeader: 'content-length'.
length ifNotNil: [ length := length asNumber ].
type := sock getHeader: 'content-type'.
sock responseCode first = $3 ifTrue: [
newUrl := sock getHeader: 'location'.
newUrl ifNotNil: [
Transcript show: 'redirecting to ', newUrl; cr.
sock destroy.
newUrl := self expandUrl: newUrl ip: serverAddr port: connectToPort.
^self httpGetDocument: newUrl args: args accept: mimeType request: requestString] ].
aStream := sock getRestOfBuffer: firstData totalLength: length.
"a 400-series error"
sock responseCode first = $4 ifTrue: [^ header, aStream contents].
].
sock destroy. "Always OK to destroy!!"
aStream class ~~ String ifTrue: [
^ MIMEDocument contentType: type content: aStream contents url: url].
aStream = 'server aborted early' ifTrue: [ ^aStream ].
].
{'HTTPSocket class>>httpGetDocument:args:accept:request:'. aStream. url} inspect.
^'some other bad thing happened!!'!
Item was added:
+ ----- Method: HTTPSocket class>>digestFor:method:url:user:password: (in category 'digest') -----
+ digestFor: serverText method: method url: url user: user password: password
+ "RFC2069"
+ | sock |
+ sock := HTTPSocket new. "header decoder is on instance side"
+ sock header: (serverText readStream upToAll: String crlf, String crlf).
+ ^self digestFrom: sock method: method url: url user: user password: password!
Item was changed:
----- Method: HTTPSocket class>>httpGet:args:user:passwd: (in category 'get the page') -----
httpGet: url args: args user: user passwd: passwd
+
+ | authorization result |
- | authorization |
authorization := (user , ':' , passwd) base64Encoded.
+ result := self
+ httpGet: url args: args accept: '*/*'
+ request: 'Authorization: Basic ' , authorization , CrLf.
+ result isString ifFalse: [^result].
+
+ authorization := self digestFor: result method: 'GET' url: url user: user password: passwd.
+ authorization ifNil: [^result].
^self
httpGet: url args: args accept: '*/*'
+ request: 'Authorization: Digest ' , authorization , CrLf!
- request: 'Authorization: Basic ' , authorization , CrLf!
Item was added:
+ ----- Method: HTTPSocket class>>md5Hash: (in category 'digest') -----
+ md5Hash: aString
+ "Answer hash of aString as lowercase 32 digit hex String.
+ There are several providers of MD5 hash ..."
+ "(self md5Hash: 'user:realm:passwd') = '007e68e539ed680c24f6d9a370f3bcb1'"
+ | hash |
+ hash := Smalltalk at: #CMD5Hasher ifPresent: [:cls |
+ cls hashMessage: aString].
+ hash ifNil: [
+ hash := Smalltalk at: #TCryptoRandom ifPresent: [:cls |
+ (cls basicNew md5HashMessage: aString) asInteger]].
+ hash ifNotNil: [
+ hash := hash hex asLowercase.
+ (hash beginsWith: '16r') ifTrue: [hash := hash allButFirst: 3].
+ hash := hash padded: #left to: 32 with: $0].
+ ^hash!
Item was changed:
----- Method: HTTPSocket class>>httpPut:to:user:passwd: (in category 'get the page') -----
httpPut: contents to: url user: user passwd: passwd
"Upload the contents of the stream to a file on the server"
+ | bare serverName specifiedServer port page serverAddr authorization s list header firstData length aStream command digest |
- | bare serverName specifiedServer port page serverAddr authorization s list header firstData length aStream command |
Socket initializeNetwork.
"parse url"
bare := (url asLowercase beginsWith: 'http://')
ifTrue: [url copyFrom: 8 to: url size]
ifFalse: [url].
serverName := bare copyUpTo: $/.
specifiedServer := serverName.
(serverName includes: $:) ifFalse: [ port := self defaultPort ] ifTrue: [
port := (serverName copyFrom: (serverName indexOf: $:) + 1
to: serverName size) asNumber.
serverName := serverName copyUpTo: $:.
].
page := bare copyFrom: (bare indexOf: $/) to: bare size.
page size = 0 ifTrue: [page := '/'].
(self shouldUseProxy: serverName) ifTrue: [
page := 'http://', serverName, ':', port printString, page. "put back together"
serverName := self httpProxyServer.
port := self httpProxyPort].
"make the request"
serverAddr := NetNameResolver addressForName: serverName timeout: 20.
serverAddr ifNil: [
^ 'Could not resolve the server named: ', serverName].
+ authorization := ' Basic ', (user , ':' , passwd) base64Encoded.
+ [
- authorization := (user , ':' , passwd) base64Encoded.
s := HTTPSocket new.
s connectTo: serverAddr port: port.
s waitForConnectionUntil: self standardDeadline.
Transcript cr; show: url; cr.
command :=
'PUT ', page, ' HTTP/1.0', CrLf,
self userAgentString, CrLf,
'Host: ', specifiedServer, CrLf,
'ACCEPT: */*', CrLf,
HTTPProxyCredentials,
+ 'Authorization: ' , authorization , CrLf ,
- 'Authorization: Basic ' , authorization , CrLf ,
'Content-length: ', contents size printString, CrLf , CrLf ,
contents.
s sendCommand: command.
"get the header of the reply"
+ list := s getResponseUpTo: CrLf, CrLf ignoring: String cr. "list = header, CrLf, CrLf, beginningOfData"
- list := s getResponseUpTo: CrLf, CrLf ignoring: (String with: CR). "list = header, CrLf, CrLf, beginningOfData"
header := list at: 1.
"Transcript show: page; cr; show: argsStream contents; cr; show: header; cr."
firstData := list at: 3.
"dig out some headers"
s header: header.
+
+ (authorization beginsWith: 'Digest ') not
+ and: [(digest := self digestFrom: s method: 'PUT' url: url user: user password: passwd) notNil]]
+ whileTrue: [authorization := 'Digest ', digest].
- length := s getHeader: 'content-length'.
- length ifNotNil: [ length := length asNumber ].
-
- aStream := s getRestOfBuffer: firstData totalLength: length.
- s destroy. "Always OK to destroy!!"
+ length := s getHeader: 'content-length'.
+ length ifNotNil: [ length := length asNumber ].
+
+ aStream := s getRestOfBuffer: firstData totalLength: length.
+ s destroy. "Always OK to destroy!!"
^ header, aStream contents!
Item was added:
+ ----- Method: HTTPSocket class>>digestFrom:method:url:user:password: (in category 'digest') -----
+ digestFrom: sock method: method url: url user: user password: password
+ "RFC2069"
+ | auth fields realm nonce uri a1 a2 response |
+ sock responseCode = '401' ifFalse: [^nil].
+ auth := sock getHeader: 'www-authenticate'.
+ (auth asLowercase beginsWith: 'digest') ifFalse: [^nil].
+
+ fields := (((auth allButFirst: 6) findTokens: ', ') collect: [:ea |
+ (ea copyUpTo: $=) asLowercase -> (ea copyAfter: $=) withoutQuoting]) as: Dictionary.
+
+ realm := fields at: 'realm'.
+ nonce := fields at: 'nonce'.
+ uri := url readStream upToAll: '://'; skipTo: $/; skip: -1; upTo: $#.
+ a1 := self md5Hash: user, ':', realm, ':', password.
+ a2 := self md5Hash: method, ':', uri.
+ a1 ifNil: [^nil "no MD5 support"].
+ response := self md5Hash: a1, ':', nonce, ':', a2.
+
+ ^String streamContents: [:digest |
+ digest
+ nextPutAll: 'username="', user, '"';
+ nextPutAll: ', realm="', realm, '"';
+ nextPutAll: ', nonce="', nonce, '"';
+ nextPutAll: ', uri="', uri, '"';
+ nextPutAll: ', response="', response, '"'.
+ fields at: 'opaque' ifPresent: [:opaque |
+ digest nextPutAll: ', opaque="', opaque, '"'].
+ ]
+ !
More information about the Squeak-dev
mailing list
|