Andreas Raab uploaded a new version of Network to project The Trunk:
http://source.squeak.org/trunk/Network-ar.77.mcz ==================== Summary ==================== Name: Network-ar.77 Author: ar Time: 2 August 2010, 7:01:43.782 pm UUID: 188c5481-3b63-9b44-b341-1c4683784f9b Ancestors: Network-ar.76 Rewrite SocketStream>>upTo: and #upToAll: to fix a VBB (Very Bad Bug) which would cause it to go into an infinite loop if the remote closed the connection before the entity was found and also make the limit argument explicit since it can often be used more effectively (i.e., a 100k limit for reading an HTTP header is probably unnecessary). =============== Diff against Network-ar.76 =============== Item was changed: ----- Method: SocketStream>>upTo: (in category 'stream in') ----- upTo: aCharacterOrByte + "Answer a subcollection from the current access position to the occurrence (if any, but not inclusive) of anObject in the receiver. If anObject is not in the collection, answer the entire rest of the receiver." - "Return data up to, but not including given character or byte. - - NOTE: Does not honour timeouts if shouldSignal is false!! - - This method looks a bit complicated, and this is mainly because there is no fast search method - in String that takes a stoppingAt: argument. This means we need to ignore getting hits in the - dead buffer area above inNextToWrite. - Another measure is that this implementation is greedy and will load data into the buffer - until there is nothing more available, or it has loaded 100kb - and not until then we search the buffer. + "Note: The 100k limit below is compatible with the previous version though arguably incorrect. If you need unbounded behavior either up the argument or provide nil in which case we'll read until we get it or run out of memory" - A totally non greedy variant would search on every loop." + ^self upTo: aCharacterOrByte limit: 100000! - | index result lastRecentlyRead searchedSoFar | - searchedSoFar := 0. - lastRecentlyRead := 0. - index := 0. - [self atEnd not and: [ - ((lastRecentlyRead = 0 and: [self isInBufferEmpty not]) or: [self inBufferSize > 100000]) ifTrue: [ - "Data begins at lastRead + 1, we add searchedSoFar as offset." - index := inBuffer indexOf: aCharacterOrByte startingAt: lastRead + searchedSoFar + 1. - searchedSoFar := self inBufferSize. - (index > 0 and: [(index + 1) > inNextToWrite]) ifTrue: [ - "Oops, hit in dead buffer area. - This is probably due to old data, so we ignore it. - No point in cleaning the dead area to avoid hits - it will still search it." - index := 0]]. - index = 0]] - whileTrue: [ - recentlyRead = 0 - ifTrue: ["blocking call for now, we don't want to poll" - self receiveData] - ifFalse: [ - self receiveAvailableData]. - lastRecentlyRead := recentlyRead]. - index > 0 - ifTrue: ["found it" - result := self nextInBuffer: index - lastRead - 1. - self skip: 1. - ^ result] - ifFalse: ["atEnd" - ^ self nextAllInBuffer]! Item was added: + ----- Method: SocketStream>>upToAll:limit: (in category 'stream in') ----- + upToAll: aStringOrByteArray limit: nBytes + "Answer a subcollection from the current access position to the occurrence (if any, but not inclusive) of aStringOrByteArray. If aCollection is not in the stream, or not found within nBytes answer the available contents of the stream" + + | index sz result searchedSoFar | + sz := aStringOrByteArray size. + "Look in the current inBuffer first" + index := inBuffer indexOfSubCollection: aStringOrByteArray + startingAt: lastRead - sz + 2. + (index > 0 and: [(index + sz) <= inNextToWrite]) ifTrue: ["found it" + result := self nextInBuffer: index - lastRead - 1. + self skip: sz. + ^ result + ]. + + [searchedSoFar := self inBufferSize. + "Receive more data" + self receiveData. + recentlyRead > 0] whileTrue:[ + + "Data begins at lastRead + 1, we add searchedSoFar as offset and + backs up sz - 1 so that we can catch any borderline hits." + + index := inBuffer indexOfSubCollection: aStringOrByteArray + startingAt: (lastRead + searchedSoFar - sz + 2 max: 1). + (index > 0 and: [(index + sz) <= inNextToWrite]) ifTrue: ["found it" + result := self nextInBuffer: index - lastRead - 1. + self skip: sz. + ^ result + ]. + "Check if we've exceeded the max. amount" + (nBytes notNil and:[inNextToWrite - lastRead > nBytes]) + ifTrue:[^self nextAllInBuffer]. + ]. + + "not found and (non-signaling) connection was closed" + ^self nextAllInBuffer! Item was changed: ----- Method: SocketStream>>upToAll: (in category 'stream in') ----- upToAll: aStringOrByteArray + "Answer a subcollection from the current access position to the occurrence (if any, but not inclusive) of aCollection. If aCollection is not in the stream, answer the entire rest of the stream." - "Answer a subcollection from the current access position to the occurrence (if any, but not - inclusive) of aStringOrByteArray. If aCollection is not in the stream, answer the entire rest of - the stream. - - NOTE: Does not honour timeouts if shouldSignal is false!! - - This method looks a bit complicated, and this is mainly because there is no fast search method - in String that takes a stoppingAt: argument. This means we need to ignore getting hits in the - dead buffer area above inNextToWrite. - Another measure is that this implementation is greedy and will load data into the buffer - until there is nothing more available, or it has loaded 100kb - and not until then we search the buffer. + "Note: The 100k limit below is compatible with the previous version though arguably incorrect. If you need unbounded behavior either up the argument or provide nil in which case we'll read until we get it or run out of memory" - A totally non greedy variant would search on every loop." + ^self upToAll: aStringOrByteArray limit: 100000! - | index sz result lastRecentlyRead searchedSoFar | - sz := aStringOrByteArray size. - searchedSoFar := 0. - lastRecentlyRead := 0. - index := 0. - [self atEnd not and: [ - ((lastRecentlyRead = 0 and: [self isInBufferEmpty not]) or: [self inBufferSize > 100000]) ifTrue: [ - "Data begins at lastRead + 1, we add searchedSoFar as offset and backs up sz - 1 - so that we can catch any borderline hits." - index := inBuffer indexOfSubCollection: aStringOrByteArray - startingAt: lastRead + searchedSoFar - sz + 2. - searchedSoFar := self inBufferSize. - (index > 0 and: [(index + sz) > inNextToWrite]) ifTrue: [ - "Oops, hit partially or completely in dead buffer area. - This is probably due to old data, so we ignore it. - No point in cleaning the dead area to avoid hits - it will still search it." - index := 0]]. - index = 0]] - whileTrue: [ - recentlyRead = 0 - ifTrue: ["blocking call for now, we don't want to poll" - self receiveData] - ifFalse: [ - self receiveAvailableData]. - lastRecentlyRead := recentlyRead]. - index > 0 - ifTrue: ["found it" - result := self nextInBuffer: index - lastRead - 1. - self skip: sz. - ^ result] - ifFalse: ["atEnd" - ^ self nextAllInBuffer]! Item was added: + ----- Method: SocketStream>>upTo:limit: (in category 'stream in') ----- + upTo: aCharacterOrByte limit: nBytes + "Return data up to, but not including given character or byte. If the character is not in the stream, or not found within nBytes answer the available contents of the stream" + + | index result searchedSoFar | + "Look in the current inBuffer first" + index := inBuffer indexOf: aCharacterOrByte startingAt: lastRead + 1. + + (index > 0 and: [(index + 1) <= inNextToWrite]) ifTrue: ["found it" + result := self nextInBuffer: index - lastRead - 1. + self skip: 1. + ^ result + ]. + + [searchedSoFar := self inBufferSize. + "Receive more data" + self receiveData. + "We only get recentlyRead = 0 in the case of a non-signaling socket close." + recentlyRead > 0] whileTrue:[ + "Data begins at lastRead + 1, we add searchedSoFar as offset." + + index := inBuffer indexOf: aCharacterOrByte + startingAt: (lastRead + searchedSoFar + 1). + (index > 0 and: [(index + 1) <= inNextToWrite]) ifTrue: ["found it" + result := self nextInBuffer: index - lastRead - 1. + self skip: 1. + ^ result + ]. + + "Check if we've exceeded the max. amount" + (nBytes notNil and:[inNextToWrite - lastRead > nBytes]) + ifTrue:[^self nextAllInBuffer]. + ]. + + "not found and (non-signaling) connection was closed" + ^self nextAllInBuffer! |
Free forum by Nabble | Edit this page |