Code archives/Networking/Modified HTTPStream

This code has been declared by its author to be Public Domain code.

Download source code

Modified HTTPStream by JoshK2008
BRL's HTTPStream module always returns a string, even when the file is not found. This can cause errors in loading routines. This modification adds an optional globl variable that will attempt to detect rejected requests and return Null.
Strict

Module BRL.HTTPStream

ModuleInfo "Version: 1.05"
ModuleInfo "Author: Mark Sibly"
ModuleInfo "License: Blitz Shared Source Code"
ModuleInfo "Copyright: Blitz Research Ltd"
ModuleInfo "Modserver: BRL"

ModuleInfo "History: 1.04 Release"
ModuleInfo "1.03: Added optional check for existing file"
ModuleInfo "1.04: Improved checking"
ModuleInfo "1.05: Went back to my way of checking for 401 and 404 errors and added optional username/password"
ModuleInfo "1.06: Did the 200 check the right way!"

Import BRL.SocketStream

'---------------------------------------------

Import "base64.bmx"

Global HTTPStreamFactoryCheckIfExists:Int
Global HTTPStreamFactoryUsername$
Global HTTPStreamFactoryPassword$

'---------------------------------------------


Type THTTPStreamFactory Extends TStreamFactory

	Method CreateStream:TStream( url:Object,proto$,path$,readable,writeable )
		If proto="http"
		
			Local i=path.Find( "/",0 ),server$,file$
			If i<>-1
				server=path[..i]
				file=path[i..]
			Else
				server=path
				file="/"
			EndIf
			
			Local stream:TStream=TSocketStream.CreateClient( server,80 )
			If Not stream Return
			
			stream.WriteLine "GET "+file+" HTTP/1.0"
			stream.WriteLine "Host: "+server
			
			
			'---------------------------------------------
			
			If HTTPStreamFactoryUsername<>"" And HTTPStreamFactoryPassword<>""
				Local s$=HTTPStreamFactoryUsername+":"+HTTPStreamFactoryPassword
				Local cs:Byte Ptr
				cs=s.tocstring()
				s=TBase64.encode(cs,s.length)
				MemFree cs
				stream.WriteLine "Authorization: Basic "+s
			EndIf
			
			'---------------------------------------------
			
			
			stream.WriteLine ""
			
			
			'---------------------------------------------
			
			If HTTPStreamFactoryCheckIfExists
				If Not s.contains("200")
					stream.close()
					Return
				EndIf
			EndIf
			
			'---------------------------------------------
			
			
			While Not Eof( stream )
				If Not stream.ReadLine() Exit				
			Wend

			Return stream
		EndIf
	End Method

End Type

New THTTPStreamFactory

Comments

SebHoll2008
I'm not sure this is a good way to go about it - if I'm reading it right, it will return Null no matter where 404 is in the document. For example, linking to this page will incorrectly return Null due to the presence of your string literal.


Yan2008
It's just dumping the header. The 'If Not s Exit' jumps out of the loop at the header's terminator, delivering the 'de-headered' stream ready for consumption.


You only need to check the first line of the header for '200'. That's always worked for me, at least.

Look here for examples.


JoshK2008
Okay, I updated the code.


JoshK2008
I don't know where you are getting this "200" from. This is what the header looks like for me:

HTTP/1.1 404 Not Found
Date: Wed, 11 Jun 2008 19:14:53 GMT
Server: Apache
Connection: close
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<HTML><HEAD>
<TITLE>404 Not Found</TITLE>
</HEAD><BODY>
<H1>Not Found</H1>
The requested URL /ppop was not found on this server.<P>
<P>Additionally, a 404 Not Found
error was encountered while trying to use an ErrorDocument to handle the request.
<HR>
<ADDRESS>Apache/1.3.33 Server at leadwerks.com Port 80</ADDRESS>
</BODY></HTML>


JoshK2008
Added optional username and password. Requires the file from bah.base64:

SuperStrict

Rem
bbdoc: Base64
End Rem
'Module BaH.Base64

'ModuleInfo "Version: 1.00"
'ModuleInfo "License: MIT"
'ModuleInfo "Copyright: Original - Robert Harder (http://iharder.sourceforge.net/current/java/base64/)"
'ModuleInfo "Copyright: BlitzMax port - 2008 Bruce A Henderson"

'ModuleInfo "History: 1.00 Initial Release"

Rem
bbdoc: Encode/Decode Base64 data.
about:
To Encode :
<pre>
SuperStrict
Import BaH.Base64

Local someData:String = "Woo! BlitzMax Modules rock!"
Local encoded:String = TBase64.Encode(someData, someData.length)
Print "Encoded : " + encoded
</pre>
To Decode :
<pre>
SuperStrict
Import BaH.Base64

Local encodedData:String = "V29vISBCbGl0ek1heCBNb2R1bGVzIHJvY2sh"
Local data:Byte[] = TBase64.Decode(encodedData)
Local decoded:String = String.FromBytes(data, data.length)
Print "Decoded : " + decoded
</pre>
End Rem
Type TBase64

	Const DONT_BREAK_LINES:Int = 8
	
	' Maximum line length (76) of Base64 output.
	Const MAX_LINE_LENGTH:Int = 76
	
	' The equals sign (=) as int.
	Const EQUALS_SIGN:Int = Asc("=")
	
	' The new line character (\n) as int.
	Const NEW_LINE:Int = Asc("~n")
	
	Const WHITE_SPACE_ENC:Int = -5 ' Indicates white space in encoding
	Const EQUALS_SIGN_ENC:Int = -1 ' Indicates equals sign in encoding
	
	Const _STANDARD_ALPHABET:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
	
	Global _STANDARD_DECODABET:Int[] = [-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
						        -5,-5, ..
						        -9,-9, ..
						        -5, ..
						        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
						        -9,-9,-9,-9,-9, ..
						        -5, ..
						        -9,-9,-9,-9,-9,-9,-9,-9,-9,-9, ..
						        62, ..
						        -9,-9,-9, ..
						        63, ..
						        52,53,54,55,56,57,58,59,60,61, ..
						        -9,-9,-9, ..
						        -1, ..
						        -9,-9,-9, ..
						        0,1,2,3,4,5,6,7,8,9,10,11,12,13, ..
						        14,15,16,17,18,19,20,21,22,23,24,25, ..    
						        -9,-9,-9,-9,-9,-9, ..
						        26,27,28,29,30,31,32,33,34,35,36,37,38, ..
						        39,40,41,42,43,44,45,46,47,48,49,50,51, ..
						        -9,-9,-9,-9]
	
	Rem
	bbdoc: Encode byte data to a Base64 encoded String, starting at @offset of @length bytes.
	End Rem
	Function Encode:String( source:Byte Ptr, length:Int, offset:Int = 0, options:Int = 0)
    
		' Isolate options
		Local dontBreakLines:Int =  options & DONT_BREAK_LINES 
		
		' Convert option To boolean in way that code likes it.
		Local breakLines:Int = True
		If dontBreakLines Then
			breakLines = False
		End If
		
		Local len43:Int = length * 4 / 3
		Local nl:Int = len43 / MAX_LINE_LENGTH
		Local pad:Int = 0
		If length Mod 3 > 0 Then
			pad = 4
		End If
		
		If Not breakLines Then
			nl = 0
		End If
		
		Local outBuff:Byte[] = New Byte[ len43 + pad + nl ]     
		Local d:Int = 0
		Local e:Int = 0
		Local len2:Int = length - 2
		Local lineLength:Int = 0
		While d < len2
			encode3to4( source, d + offset, 3, outBuff, e, options )
			
			lineLength :+ 4
			If  breakLines And (lineLength = MAX_LINE_LENGTH) Then
				outBuff[e+4] = NEW_LINE
				e:+1
				lineLength = 0
			End If
			d:+3
			e:+4
		Wend
		
		' pad?
		If d < Length Then
			encode3to4( source, d + offset, Length - d, outBuff, e, options )
			e :+ 4
		End If
		
		Return String.FromBytes(outBuff, outBuff.length)
	End Function
	
	Rem
	bbdoc: Decode Base64 encoded String to an array of Bytes, starting at @offset.
	End Rem
	Function Decode:Byte[]( source:String, offset:Int = 0, options:Int = 0 )
		
		Local length:Int = source.length
		Local len34:Int   = Length * 3 / 4
		Local outBuff:Byte[] = New Byte[ len34 ]
		Local outBuffPosn:Int = 0
		
		Local b4:Byte[]     = New Byte[4]
		Local b4Posn:Int    = 0
		Local sbiCrop:Int   = 0
		Local sbiDecode:Int = 0
		For Local i:Int = offset Until offset + length
		
			sbiCrop = source[i] & $7f
			sbiDecode = _STANDARD_DECODABET[ sbiCrop ]
			
			If sbiDecode >= WHITE_SPACE_ENC Then
			
				If sbiDecode >= EQUALS_SIGN_ENC Then
				
					b4[ b4Posn ] = sbiCrop
					b4Posn:+1
					If b4Posn > 3 Then
				
						outBuffPosn :+ decode4to3( b4, 0, outBuff, outBuffPosn, options )
						b4Posn = 0
				
						' If that was the equals sign, break out of 'for' loop
						If sbiCrop = EQUALS_SIGN Then
							Exit
						End If
					End If
			
				End If
			
			Else
				DebugLog "Bad Base64 input character at " + i + ": " + source[i]
				Return Null
			End If
		Next
		
		Return outBuff[0..outBuffPosn]
	End Function

	Function encode3to4:Byte[](source:Byte Ptr, srcOffset:Int, numSigBytes:Int, destination:Byte[], destOffset:Int, options:Int )
    
		Local inBuff:Int
		If numSigBytes > 0 Then
			inBuff = (source[ srcOffset     ] Shl 24) Shr 8
			
			If numSigBytes > 1 Then
				inBuff :| (source[ srcOffset + 1 ] Shl 24) Shr 16

				If numSigBytes > 2 Then
					inBuff :| (source[ srcOffset + 2 ] Shl 24) Shr 24
				End If
			End If
		End If
		
		Select numSigBytes
			Case 3
				destination[ destOffset     ] = _STANDARD_ALPHABET[ (inBuff Shr 18)       ]
				destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
				destination[ destOffset + 2 ] = _STANDARD_ALPHABET[ (inBuff Shr  6) & $3f ]
				destination[ destOffset + 3 ] = _STANDARD_ALPHABET[ (inBuff       ) & $3f ]
				Return destination
			
			Case 2
				destination[ destOffset     ] = _STANDARD_ALPHABET[ (inBuff Shr 18)       ]
				destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
				destination[ destOffset + 2 ] = _STANDARD_ALPHABET[ (inBuff Shr  6) & $3f ]
				destination[ destOffset + 3 ] = EQUALS_SIGN
				Return destination
			
			Case 1
				destination[ destOffset     ] = _STANDARD_ALPHABET[ (inBuff Shr 18)       ]
				destination[ destOffset + 1 ] = _STANDARD_ALPHABET[ (inBuff Shr 12) & $3f ]
				destination[ destOffset + 2 ] = EQUALS_SIGN
				destination[ destOffset + 3 ] = EQUALS_SIGN
				Return destination
			
			Default
				Return destination
		End Select
	End Function 
	
	Function decode4to3:Int( source:Byte[] , srcOffset:Int, destination:Byte[] , destOffset:Int, options:Int )
	
		' Example: Dk==
		If source[ srcOffset + 2] = EQUALS_SIGN Then
		
			Local outBuff:Int =   ( ( _STANDARD_DECODABET[ source[ srcOffset    ] ] & $FF ) Shl 18 ) ..
				| ( ( _STANDARD_DECODABET[ source[ srcOffset + 1] ] & $FF ) Shl 12 )
			
			destination[ destOffset ] = outBuff Shr 16
			Return 1
		
		' Example: DkL=
		Else If source[ srcOffset + 3 ] = EQUALS_SIGN Then
		
			Local outBuff:Int =   ( ( _STANDARD_DECODABET[ source[ srcOffset     ] ] & $FF ) Shl 18 ) ..
				| ( ( _STANDARD_DECODABET[ source[ srcOffset + 1 ] ] & $FF ) Shl 12 ) ..
				| ( ( _STANDARD_DECODABET[ source[ srcOffset + 2 ] ] & $FF ) Shl  6 )
			
			destination[ destOffset     ] = outBuff Shr 16
			destination[ destOffset + 1 ] = outBuff Shr  8
			Return 2
			
		' Example: DkLE
		Else
		
			Local outBuff:Int =   ( ( _STANDARD_DECODABET[ source[ srcOffset     ] ] & $FF ) Shl 18 ) ..
				| ( ( _STANDARD_DECODABET[ source[ srcOffset + 1 ] ] & $FF ) Shl 12 ) ..
				| ( ( _STANDARD_DECODABET[ source[ srcOffset + 2 ] ] & $FF ) Shl  6) ..
				| ( ( _STANDARD_DECODABET[ source[ srcOffset + 3 ] ] & $FF )      )
		
			destination[ destOffset     ] =  outBuff Shr 16
			destination[ destOffset + 1 ] =  outBuff Shr  8
			destination[ destOffset + 2 ] =  outBuff
		
			Return 3
		End If
	End Function 

End Type



ShadowTurtle2008
see follow link and have fun: ^^
http://www.google.com/support/webmasters/bin/answer.py?hl=en&answer=40132

status code 200 means ...

" 200 (Successful) The server successfully processed the request. Generally, this means that the server provided the requested page. If you see this status for your robots.txt file, it means that Googlebot retrieved it successfully. "


JoshK2008
The header my prog returns does not contain that.


JoshK2008
OHHHH, I see, 200 means it worked! Fixed now.


Code Archives Forum