1 52 53 package com.go.trove.net; 54 55 import java.net.*; 56 import java.io.*; 57 import java.util.*; 58 import com.go.trove.io.*; 59 60 66 public class HttpClient { 67 private final SocketFactory mFactory; 68 private final int mReadTimeout; 69 70 private String mMethod = "GET"; 71 private String mURI = ""; 72 private String mProtocol = "HTTP/1.0"; 73 private HttpHeaderMap mHeaders; 74 75 private Object mSession; 76 77 83 public HttpClient(SocketFactory factory) { 84 this(factory, factory.getDefaultTimeout()); 85 } 86 87 92 public HttpClient(SocketFactory factory, long readTimeout) { 93 mFactory = factory; 94 if (readTimeout == 0) { 95 mReadTimeout = 1; 96 } 97 else if (readTimeout < 0) { 98 mReadTimeout = 0; 99 } 100 else if (readTimeout > Integer.MAX_VALUE) { 101 mReadTimeout = Integer.MAX_VALUE; 102 } 103 else { 104 mReadTimeout = (int)readTimeout; 105 } 106 } 107 108 113 public HttpClient setMethod(String method) { 114 mMethod = method; 115 return this; 116 } 117 118 123 public HttpClient setURI(String uri) { 124 mURI = uri; 125 return this; 126 } 127 128 133 public HttpClient setProtocol(String protocol) { 134 mProtocol = protocol; 135 return this; 136 } 137 138 143 public HttpClient setHeader(String name, Object value) { 144 if (mHeaders == null) { 145 mHeaders = new HttpHeaderMap(); 146 } 147 mHeaders.put(name, value); 148 return this; 149 } 150 151 157 public HttpClient addHeader(String name, Object value) { 158 if (mHeaders == null) { 159 mHeaders = new HttpHeaderMap(); 160 } 161 mHeaders.add(name, value); 162 return this; 163 } 164 165 172 public HttpClient setHeaders(HttpHeaderMap headers) { 173 mHeaders = headers; 174 return this; 175 } 176 177 184 public HttpClient setPersistent(boolean b) { 185 if (b) { 186 setHeader("Connection", "Keep-Alive"); 187 } 188 else { 189 setHeader("Connection", "Close"); 190 } 191 return this; 192 } 193 194 203 public HttpClient preparePost(int contentLength) { 204 setMethod("POST"); 205 setHeader("Content-Type", "application/x-www-form-urlencoded"); 206 setHeader("Content-Length", new Integer (contentLength)); 207 return this; 208 } 209 210 219 public HttpClient setSession(Object session) { 220 mSession = session; 221 return this; 222 } 223 224 228 public Response getResponse() throws ConnectException, SocketException { 229 return getResponse(null); 230 } 231 232 242 public Response getResponse(PostData postData) 243 throws ConnectException, SocketException 244 { 245 CheckedSocket socket = mFactory.getSocket(mSession); 246 socket.setSoTimeout(mReadTimeout); 247 248 try { 249 CharToByteBuffer buffer = new FastCharToByteBuffer 250 (new DefaultByteBuffer(), "8859_1"); 251 buffer = new InternedCharToByteBuffer(buffer); 252 253 buffer.append(mMethod); 254 buffer.append(' '); 255 buffer.append(mURI); 256 buffer.append(' '); 257 buffer.append(mProtocol); 258 buffer.append("\r\n"); 259 if (mHeaders != null) { 260 mHeaders.appendTo(buffer); 261 } 262 buffer.append("\r\n"); 263 264 OutputStream out; 265 InputStream in; 266 267 out = new FastBufferedOutputStream(socket.getOutputStream()); 268 buffer.writeTo(out); 269 if (postData != null) { 270 writePostData(out, postData); 271 } 272 out.flush(); 273 in = new FastBufferedInputStream(socket.getInputStream()); 274 275 char[] buf = new char[100]; 277 String line; 278 try { 279 line = HttpUtils.readLine(in, buf); 280 } 281 catch (IOException e) { 282 line = null; 283 } 284 285 if (line == null) { 286 try { 288 socket.close(); 289 } 290 catch (IOException e) { 291 } 292 293 socket = mFactory.createSocket(mSession); 294 socket.setSoTimeout(mReadTimeout); 295 296 out = new FastBufferedOutputStream(socket.getOutputStream()); 297 buffer.writeTo(out); 298 if (postData != null) { 299 writePostData(out, postData); 300 } 301 out.flush(); 302 in = new FastBufferedInputStream(socket.getInputStream()); 303 304 if ((line = HttpUtils.readLine(in, buf)) == null) { 306 throw new ConnectException("No response from server"); 307 } 308 } 309 310 return new Response(socket, mMethod, in, buf, line); 311 } 312 catch (SocketException e) { 313 throw e; 314 } 315 catch (InterruptedIOException e) { 316 throw new ConnectException("Read timeout expired: " + 317 mReadTimeout + ", " + e); 318 } 319 catch (IOException e) { 320 throw new SocketException(e.toString()); 321 } 322 } 323 324 private void writePostData(OutputStream out, PostData postData) 325 throws IOException 326 { 327 InputStream in = postData.getInputStream(); 328 329 int contentLength = -1; 330 if (mHeaders != null) { 331 Integer i = mHeaders.getInteger("Content-Length"); 332 if (i != null) { 333 contentLength = i.intValue(); 334 } 335 } 336 337 byte[] buf; 338 if (contentLength < 0 || contentLength > 4000) { 339 buf = new byte[4000]; 340 } 341 else { 342 buf = new byte[contentLength]; 343 } 344 345 try { 346 int len; 347 if (contentLength < 0) { 348 while ((len = in.read(buf)) > 0) { 349 out.write(buf, 0, len); 350 } 351 } 352 else { 353 while (contentLength > 0) { 354 len = buf.length; 355 if (contentLength < len) { 356 len = contentLength; 357 } 358 if ((len = in.read(buf, 0, len)) <= 0) { 359 break; 360 } 361 out.write(buf, 0, len); 362 contentLength -= len; 363 } 364 } 365 } 366 finally { 367 in.close(); 368 } 369 } 370 371 374 public static interface PostData { 375 380 public InputStream getInputStream() throws IOException; 381 } 382 383 public class Response { 384 private final int mStatusCode; 385 private final String mStatusMessage; 386 private final HttpHeaderMap mHeaders; 387 388 private InputStream mIn; 389 390 Response(CheckedSocket socket, String method, 391 InputStream in, char[] buf, String line) throws IOException 392 { 393 int statusCode = -1; 394 String statusMessage = ""; 395 396 int space = line.indexOf(' '); 397 if (space > 0) { 398 int nextSpace = line.indexOf(' ', space + 1); 399 String sub; 400 if (nextSpace < 0) { 401 sub = line.substring(space + 1); 402 } 403 else { 404 sub = line.substring(space + 1, nextSpace); 405 statusMessage = line.substring(nextSpace + 1); 406 } 407 try { 408 statusCode = Integer.parseInt(sub); 409 } 410 catch (NumberFormatException e) { 411 } 412 } 413 414 if (statusCode < 0) { 415 throw new ProtocolException("Invalid HTTP response: " + line); 416 } 417 418 mStatusCode = statusCode; 419 mStatusMessage = statusMessage; 420 mHeaders = new HttpHeaderMap(); 421 mHeaders.readFrom(in, buf); 422 423 int contentLength; 425 if ("Keep-Alive".equalsIgnoreCase 426 (mHeaders.getString("Connection"))) { 427 428 if ("HEAD".equals(method)) { 429 contentLength = 0; 430 } 431 else { 432 Integer i = mHeaders.getInteger("Content-Length"); 433 if (i != null) { 434 contentLength = i.intValue(); 435 } 436 else { 437 contentLength = -1; 438 } 439 } 440 } 441 else { 442 contentLength = -1; 443 } 444 445 mIn = new ResponseInput(socket, in, contentLength); 446 } 447 448 452 public int getStatusCode() { 453 return mStatusCode; 454 } 455 456 460 public String getStatusMessage() { 461 return mStatusMessage; 462 } 463 464 public HttpHeaderMap getHeaders() { 465 return mHeaders; 466 } 467 468 475 public InputStream getInputStream() { 476 return mIn; 477 } 478 } 479 480 private class ResponseInput extends InputStream { 481 private CheckedSocket mSocket; 482 private InputStream mIn; 483 private int mContentLength; 484 485 489 public ResponseInput(CheckedSocket socket, 490 InputStream in, int contentLength) 491 throws IOException 492 { 493 mSocket = socket; 494 mIn = in; 495 if ((mContentLength = contentLength) == 0) { 496 recycle(); 497 } 498 } 499 500 public int read() throws IOException { 501 if (mContentLength == 0) { 502 return -1; 503 } 504 505 int b = mIn.read(); 506 507 if (b < 0) { 508 close(); 509 } 510 else if (mContentLength > 0) { 511 if (--mContentLength == 0) { 512 recycle(); 513 } 514 } 515 516 return b; 517 } 518 519 public int read(byte[] b) throws IOException { 520 return read(b, 0, b.length); 521 } 522 523 public int read(byte[] b, int off, int len) throws IOException { 524 if (mContentLength == 0) { 525 return -1; 526 } 527 528 if (mContentLength < 0) { 529 len = mIn.read(b, off, len); 530 if (len < 0) { 531 close(); 532 } 533 else if (len == 0) { 534 close(); 535 len = -1; 536 } 537 return len; 538 } 539 540 if (len > mContentLength) { 541 len = mContentLength; 542 } 543 else if (len == 0) { 544 return 0; 545 } 546 547 len = mIn.read(b, off, len); 548 549 if (len < 0) { 550 close(); 551 } 552 else if (len == 0) { 553 close(); 554 len = -1; 555 } 556 else { 557 if ((mContentLength -= len) == 0) { 558 recycle(); 559 } 560 } 561 562 return len; 563 } 564 565 public long skip(long n) throws IOException { 566 if (mContentLength == 0) { 567 return 0; 568 } 569 570 if (mContentLength < 0) { 571 return mIn.skip(n); 572 } 573 574 if (n > mContentLength) { 575 n = mContentLength; 576 } 577 else if (n == 0) { 578 return 0; 579 } 580 581 n = mIn.skip(n); 582 583 if ((mContentLength -= n) == 0) { 584 recycle(); 585 } 586 587 return n; 588 } 589 590 public int available() throws IOException { 591 return mIn.available(); 592 } 593 594 public void close() throws IOException { 595 if (mSocket != null) { 596 mContentLength = 0; 597 mSocket = null; 598 mIn.close(); 599 } 600 } 601 602 private void recycle() throws IOException { 603 if (mSocket != null) { 604 if (mContentLength == 0) { 605 CheckedSocket s = mSocket; 606 mSocket = null; 607 mFactory.recycleSocket(s); 608 } 609 else { 610 mSocket = null; 611 mIn.close(); 612 } 613 } 614 } 615 } 616 } 617 | Popular Tags |