[ENH][FIX] HTTP-Proxies
Michael Rueger
Michael.Rueger.-ND at disney.com
Wed Mar 1 23:02:17 UTC 2000
Change Set: ProxyFix-mir
Date: 3 August 1999
Author: Michael Rueger
Setting a proxy in Squeak usually keeps you from connecting to local hosts
within your domain. This fix adds a list of exempt host or domain names to
HTTPSocket, which should not be contacted through the proxy.
--
"To improve is to change, to be perfect is to change often."
Winston Churchill
+------------------------------------------------------------+
| Michael Rueger |
| Phone: ++1 (818) 623 3283 Fax: ++1 (818) 623 3559 |
+---------- Michael.Rueger.-ND at corp.go.com ------------------+
-------------- next part --------------
"Change Set: ProxyFix-mir
Date: 3 August 1999
Author: Michael Rueger
Setting a proxy in Squeak usually keeps you from connecting to local hosts within your domain. This fix adds a list of exempt host or domain names to HTTPSocket, which should not be contacted through the proxy.
"!
SimpleClientSocket subclass: #HTTPSocket
instanceVariableNames: 'headerTokens headers responseCode '
classVariableNames: 'HTTPBlabEmail HTTPPort HTTPProxyExceptions HTTPProxyPort HTTPProxyServer ParamDelimiters '
poolDictionaries: ''
category: 'Network-Protocols'!
Url subclass: #HierarchicalUrl
instanceVariableNames: 'schemeName authority port path query '
classVariableNames: ''
poolDictionaries: ''
category: 'Network-Url'!
!HTTPSocket class methodsFor: 'get the page' stamp: 'mir 7/30/1999 14:55'!
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'."
| httpUrl page sock list header firstData aStream length type newUrl |
Socket initializeNetwork.
httpUrl _ Url absoluteFromText: url.
page _ httpUrl toText.
"add arguments"
args ifNotNil: [page _ page, (self argString: args) ].
3 timesRepeat: [
sock _ self initHTTPSocket: httpUrl ifError: [:errorString | ^errorString].
"Transcript cr; cr; show: url."
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"
'User-Agent: Squeak 1.31', CrLf,
'Host: ', httpUrl authority, ':', httpUrl port printString, CrLf. "blank line
automatically added"
list _ sock getResponseUpTo: CrLf, CrLf. "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.
^self httpGetDocument: newUrl args: args accept: mimeType ] ].
aStream _ sock getRestOfBuffer: firstData totalLength: length.
sock responseCode = '401' 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' ifFalse: [
]
].! !
!HTTPSocket class methodsFor: 'get the page' stamp: 'mir 7/30/1999 15:44'!
httpPostDocument: url args: argsDict accept: mimeType request: requestString
"like httpGET, except it does a POST instead of a GET. POST allows data to be uploaded"
| s header length page list firstData aStream argsStream first type newUrl httpUrl |
Socket initializeNetwork.
httpUrl _ Url absoluteFromText: url.
page _ httpUrl toText.
"add arguments"
argsDict ifNotNil: [page _ page, (self argString: argsDict) ].
"encode the arguments dictionary"
argsStream _ WriteStream on: String new.
first _ true.
argsDict associationsDo: [ :assoc |
assoc value do: [ :value |
first ifTrue: [ first _ false ] ifFalse: [ argsStream nextPut: $& ].
argsStream nextPutAll: assoc key encodeForHTTP.
argsStream nextPut: $=.
argsStream nextPutAll: value encodeForHTTP.
] ].
s _ HTTPSocket new.
s _ self initHTTPSocket: httpUrl wait: (self deadlineSecs: 30) ifError: [:errorString | ^errorString].
Transcript cr; show: url; cr.
s sendCommand: 'POST ', 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"
'User-Agent: Squeak 1.31', CrLf,
'Content-type: application/x-www-form-urlencoded', CrLf,
'Content-length: ', argsStream contents size printString, CrLf,
'Host: ', httpUrl authority, CrLf. "blank line automatically added"
s sendCommand: argsStream contents.
"get the header of the reply"
list _ s getResponseUpTo: CrLf, CrLf. "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.
length _ s getHeader: 'content-length'.
length ifNotNil: [ length _ length asNumber ].
type _ s getHeader: 'content-type'.
s responseCode first = $3 ifTrue: [
newUrl _ s getHeader: 'location'.
newUrl ifNotNil: [
Transcript show: 'redirecting to: ', newUrl; cr.
s destroy.
^self httpPostDocument: newUrl args: argsDict accept: mimeType ] ].
aStream _ s getRestOfBuffer: firstData totalLength: length.
s responseCode = '401' ifTrue: [^ header, aStream contents].
s destroy. "Always OK to destroy!!"
^ MIMEDocument contentType: type content: aStream contents url: url! !
!HTTPSocket class methodsFor: 'proxy settings' stamp: 'mir 7/30/1999 16:08'!
addProxyException: domainName
"Add a (partial, wildcard) domain name to the list of proxy exceptions"
"HTTPSocket addProxyException: '*.online.disney.com'"
self httpProxyExceptions add: domainName! !
!HTTPSocket class methodsFor: 'proxy settings' stamp: 'mir 7/30/1999 15:03'!
httpProxyExceptions
HTTPProxyExceptions ifNil: [HTTPProxyExceptions _ OrderedCollection new].
^HTTPProxyExceptions! !
!HTTPSocket class methodsFor: 'proxy settings' stamp: 'mir 7/30/1999 15:03'!
removeProxyException: domainName
"Remove a (partial, wildcard) domain name from the list of proxy exceptions"
self httpProxyExceptions remove: domainName ifAbsent: []! !
!HTTPSocket class methodsFor: 'utilities' stamp: 'mir 7/30/1999 15:46'!
initHTTPSocket: httpUrl ifError: aBlock
"Retrieve the server and port information from the URL, match it to the proxy settings and open a http socket for the request."
^self initHTTPSocket: httpUrl wait: self standardDeadline ifError: aBlock! !
!HTTPSocket class methodsFor: 'utilities' stamp: 'mir 7/30/1999 15:43'!
initHTTPSocket: httpUrl wait: timeout ifError: aBlock
"Retrieve the server and port information from the URL, match it to the proxy settings and open a http socket for the request."
| serverName port serverAddr s |
Socket initializeNetwork.
serverName _ httpUrl authority.
port _ httpUrl port ifNil: [self defaultPort].
(self shouldUseProxy: serverName) ifTrue: [
serverName _ HTTPProxyServer.
port _ HTTPProxyPort].
"make the request"
self retry: [serverAddr _ NetNameResolver addressForName: serverName timeout: 20.
serverAddr ~~ nil]
asking: 'Trouble resolving server name. Keep trying?'
ifGiveUp: [aBlock value: 'Error: Could not resolve the server named: ', serverName].
s _ HTTPSocket new.
s connectTo: serverAddr port: port.
(s waitForConnectionUntil: timeout) ifFalse: [
Socket deadServer: httpUrl authority.
s destroy.
^aBlock value: 'Error: Server ',httpUrl authority,' is not responding'].
^s
! !
!HTTPSocket class methodsFor: 'utilities' stamp: 'mir 7/30/1999 13:33'!
shouldUseProxy: serverName
"Retrieve the server and port information from the URL, match it to the proxy settings and open a http socket for the request."
HTTPProxyServer ifNotNil: [
self httpProxyExceptions
detect: [:domainName | domainName match: serverName]
ifNone: [^true]].
^false
! !
!HierarchicalUrl methodsFor: 'parsing' stamp: 'mir 7/30/1999 13:05'!
privateInitializeFromText: aString
| remainder ind nextTok s specifiedSchemeName |
remainder _ aString.
schemeName ifNil: [
specifiedSchemeName _ Url schemeNameForString: remainder.
specifiedSchemeName ifNotNil: [
schemeName _ specifiedSchemeName.
remainder _ remainder copyFrom: (schemeName size+2) to: remainder size ].
schemeName ifNil: [ "assume HTTP" schemeName _ 'http' ] ].
"remove leading // if it's there"
(remainder beginsWith: '//') ifTrue: [
remainder _ remainder copyFrom: 3 to: remainder size ].
"get the query"
ind _ remainder indexOf: $?.
ind > 0 ifTrue: [
query _ (remainder copyFrom: ind+1 to: remainder size).
remainder _ remainder copyFrom: 1 to: ind-1 ].
"get the authority"
ind _ remainder indexOf: $/.
ind > 0 ifTrue: [
ind = 1 ifTrue: [ authority _ '' ] ifFalse: [
authority _ remainder copyFrom: 1 to: ind-1.
remainder _ remainder copyFrom: ind+1 to: remainder size. ] ]
ifFalse: [
authority _ remainder.
remainder _ ''. ].
"Extract the port"
(authority includes: $:)
ifTrue: [
port _ (authority copyFrom: (authority indexOf: $:) + 1 to: authority size) asNumber.
authority _ authority copyUpTo: $:].
"get the path"
path _ OrderedCollection new.
s _ ReadStream on: remainder.
[
s peek = $/ ifTrue: [ s next ].
nextTok _ WriteStream on: String new.
[ s atEnd or: [ s peek = $/ ] ] whileFalse: [ nextTok nextPut: s next ].
nextTok _ nextTok contents unescapePercents.
nextTok = '..'
ifTrue: [ path size > 0 ifTrue: [ path removeLast ] ]
ifFalse: [ nextTok ~= '.' ifTrue: [ path add: nextTok ] ].
s atEnd
] whileFalse.
path isEmpty ifTrue: [ path add: '' ].! !
!HierarchicalUrl methodsFor: 'access' stamp: 'mir 7/30/1999 13:05'!
port
^port! !
More information about the Squeak-dev
mailing list
|