001 package com.croftsoft.core.net.http; 002 003 import java.io.*; 004 import java.net.*; 005 import java.util.*; 006 007 import com.croftsoft.core.io.Parser; 008 009 /********************************************************************* 010 * Somewhat of a replacement for HttpURLConnection. 011 * 012 * <p /> 013 * 014 * @version 015 * 2003-05-19 016 * @since 017 * 2000-04-27 018 * @author 019 * <a href="https://www.croftsoft.com/">David W. Croft</a> 020 *********************************************************************/ 021 022 public final class HttpConnection 023 ////////////////////////////////////////////////////////////////////// 024 ////////////////////////////////////////////////////////////////////// 025 { 026 027 public static final int HTTP_ACCEPTED = 202; 028 029 public static final int HTTP_NO_CONTENT = 204; 030 031 private final String host; 032 033 private final int port; 034 035 private final String path; 036 037 private final String userAgent; 038 039 private final String contentType; 040 041 private byte [ ] requestBytes; 042 043 private final Parser contentParser; 044 045 // need to modify so that Headers used during outgoing posts; 046 // don't forget to clear! 047 048 private final Hashtable headerHashtable; 049 050 private int responseCode; 051 052 private Object parsedContent; 053 054 private Socket socket; 055 056 ////////////////////////////////////////////////////////////////////// 057 ////////////////////////////////////////////////////////////////////// 058 059 public HttpConnection ( 060 String host, 061 int port, 062 String path, 063 String userAgent, 064 String contentType, 065 byte [ ] requestBytes, 066 Parser contentParser ) 067 ////////////////////////////////////////////////////////////////////// 068 { 069 if ( host == null ) 070 { 071 throw new IllegalArgumentException ( "null host" ); 072 } 073 074 if ( port == -1 ) 075 { 076 port = 80; 077 } 078 079 if ( path == null ) 080 { 081 throw new IllegalArgumentException ( "null path" ); 082 } 083 084 if ( userAgent == null ) 085 { 086 throw new IllegalArgumentException ( "null userAgent" ); 087 } 088 089 if ( contentType == null ) 090 { 091 throw new IllegalArgumentException ( "null contentType" ); 092 } 093 094 this.host = host; 095 096 this.port = port; 097 098 this.path = path; 099 100 this.userAgent = userAgent; 101 102 this.contentType = contentType; 103 104 this.requestBytes = requestBytes; 105 106 this.contentParser = contentParser; 107 108 headerHashtable = new Hashtable ( ); 109 } 110 111 ////////////////////////////////////////////////////////////////////// 112 ////////////////////////////////////////////////////////////////////// 113 114 public void post ( ) 115 throws IOException 116 ////////////////////////////////////////////////////////////////////// 117 { 118 // Save a reference to requestBytes in case it gets changed. 119 120 byte [ ] requestBytes = this.requestBytes; 121 122 OutputStream out = null; 123 124 InputStream in = null; 125 126 try 127 { 128 socket = new Socket ( host, port ); 129 130 out = socket.getOutputStream ( ); 131 132 StringBuffer stringBuffer = new StringBuffer ( ); 133 134 stringBuffer.append ( "POST " + path + " HTTP/1.0\r\n" ); 135 136 stringBuffer.append ( "Connection: Keep-Alive\r\n" ); 137 138 stringBuffer.append ( "User-Agent: " + userAgent + "\r\n" ); 139 140 // What was that other one? Webmaster? 141 142 stringBuffer.append ( "Content-type: " + contentType + "\r\n" ); 143 144 if ( requestBytes != null ) 145 { 146 stringBuffer.append ( 147 "Content-length: " + requestBytes.length + "\r\n" ); 148 } 149 150 stringBuffer.append ( "\r\n" ); 151 152 // US-ASCII was here 153 out.write ( stringBuffer.toString ( ).getBytes ( ) ); 154 155 if ( requestBytes != null ) 156 { 157 out.write ( requestBytes ); 158 } 159 160 out.flush ( ); 161 162 in = socket.getInputStream ( ); 163 164 parseResponse ( in ); 165 } 166 finally 167 { 168 try 169 { 170 if ( in != null ) 171 { 172 in.close ( ); 173 } 174 } 175 catch ( Exception ex ) 176 { 177 ex.printStackTrace ( ); 178 } 179 180 try 181 { 182 if ( out != null ) 183 { 184 out.close ( ); 185 } 186 } 187 catch ( Exception ex ) 188 { 189 ex.printStackTrace ( ); 190 } 191 192 // keep-alive? 193 194 try 195 { 196 if ( socket != null ) 197 { 198 socket.close ( ); 199 } 200 } 201 catch ( Exception ex ) 202 { 203 ex.printStackTrace ( ); 204 } 205 } 206 } 207 208 public void abort ( ) 209 ////////////////////////////////////////////////////////////////////// 210 { 211 //System.out.println ( "HttpConnection.abort()" ); 212 213 try 214 { 215 if ( socket != null ) 216 { 217 socket.close ( ); 218 } 219 } 220 catch ( Exception ex ) 221 { 222 } 223 } 224 225 ////////////////////////////////////////////////////////////////////// 226 ////////////////////////////////////////////////////////////////////// 227 228 public int getResponseCode ( ) { return responseCode; } 229 230 public Object getParsedContent ( ) { return parsedContent; } 231 232 public Hashtable getHeaderHashtable ( ) { return headerHashtable; } 233 234 public void setRequestBytes ( byte [ ] requestBytes ) 235 ////////////////////////////////////////////////////////////////////// 236 { 237 this.requestBytes = requestBytes; 238 } 239 240 ////////////////////////////////////////////////////////////////////// 241 ////////////////////////////////////////////////////////////////////// 242 243 private void parseResponse ( InputStream inputStream ) 244 throws IOException 245 ////////////////////////////////////////////////////////////////////// 246 { 247 headerHashtable.clear ( ); 248 249 if ( inputStream == null ) 250 { 251 responseCode = -1; 252 253 return; 254 } 255 256 byte [ ] statusBytes = new byte [ 12 ]; 257 258 int bytesRead = inputStream.read ( statusBytes ); 259 260 if ( bytesRead < 12 ) 261 { 262 responseCode = -1; 263 264 return; 265 } 266 267 // US-ASCII was here 268 String statusString = new String ( statusBytes ); 269 270 // weak 271 if ( !statusString.startsWith ( "HTTP/1." ) ) 272 { 273 responseCode = -1; 274 275 return; 276 } 277 278 try 279 { 280 responseCode = Integer.parseInt ( statusString.substring ( 9 ) ); 281 } 282 catch ( NumberFormatException ex ) 283 { 284 responseCode = -1; 285 286 return; 287 } 288 289 readLine ( inputStream ); 290 291 String line; 292 293 while ( ( line = readLine ( inputStream ) ) != null ) 294 { 295 if ( line.equals ( "" ) ) 296 { 297 break; 298 } 299 300 int index = line.indexOf ( ":" ); 301 302 if ( index < 1 ) 303 { 304 responseCode = -1; 305 306 return; 307 } 308 309 String headerName = line.substring ( 0, index ); 310 311 if ( line.length ( ) > index + 2 ) 312 { 313 String headerValue = line.substring ( index + 2 ).trim ( ); 314 315 //System.out.println ( "HttpConnection: (\"" + headerName + "\",\"" 316 // + headerValue + "\")" ); 317 318 headerHashtable.put ( headerName, headerValue ); 319 } 320 else 321 { 322 responseCode = -1; 323 324 return; 325 } 326 } 327 328 if ( line == null ) 329 { 330 return; 331 } 332 333 if ( contentParser == null ) 334 { 335 return; 336 } 337 338 if ( ( responseCode == HTTP_ACCEPTED ) 339 || ( responseCode == HTTP_NO_CONTENT ) ) 340 { 341 return; 342 } 343 344 String contentLengthStr 345 = ( String ) headerHashtable.get ( "Content-Length" ); 346 347 int contentLength; 348 349 if ( contentLengthStr == null ) 350 { 351 contentLength = -1; 352 } 353 else 354 { 355 try 356 { 357 contentLength = Integer.parseInt ( contentLengthStr ); 358 } 359 catch ( NumberFormatException ex ) 360 { 361 responseCode = -1; 362 363 return; 364 } 365 } 366 367 if ( contentLength == 0 ) 368 { 369 return; 370 } 371 372 parsedContent = contentParser.parse ( inputStream, contentLength ); 373 } 374 375 // don't want to buffer but do want to have readLine capability; 376 // DataInputStream.readLine deprecated, BufferedReader buffers 377 378 // only works with "\r\n"; note: no pushback 379 380 private static String readLine ( InputStream inputStream ) 381 throws IOException 382 ////////////////////////////////////////////////////////////////////// 383 { 384 // looking for "\r\n" 385 386 ByteArrayOutputStream byteArrayOutputStream 387 = new ByteArrayOutputStream ( ); 388 389 int state = 0; 390 391 while ( true ) 392 { 393 int c = inputStream.read ( ); 394 395 if ( c < 0 ) 396 { 397 // encoding? 398 399 String s = byteArrayOutputStream.toString ( ); 400 401 if ( s.length ( ) < 1 ) 402 { 403 return null; 404 } 405 406 return s; 407 } 408 409 if ( c == '\r' ) 410 { 411 if ( state == 0 ) 412 { 413 state = 1; 414 } 415 else 416 { 417 state = 0; 418 } 419 } 420 else if ( c == '\n' ) 421 { 422 if ( state == 1 ) 423 { 424 // encoding? 425 426 String s = byteArrayOutputStream.toString ( ); 427 428 // trim off the "\r" 429 430 return s.substring ( 0, s.length ( ) - 1 ); 431 } 432 else 433 { 434 state = 0; 435 } 436 } 437 else 438 { 439 state = 0; 440 } 441 442 byteArrayOutputStream.write ( c ); 443 } 444 } 445 446 ////////////////////////////////////////////////////////////////////// 447 ////////////////////////////////////////////////////////////////////// 448 }