|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 package com.nokia.mj.impl.http; |
|
20 |
|
21 import java.io.ByteArrayOutputStream; |
|
22 import java.io.DataInputStream; |
|
23 import java.io.DataOutputStream; |
|
24 import java.io.IOException; |
|
25 import java.io.InputStream; |
|
26 import java.io.OutputStream; |
|
27 import java.util.Enumeration; |
|
28 import java.util.Hashtable; |
|
29 import java.util.Vector; |
|
30 import javax.microedition.io.HttpConnection; |
|
31 import com.nokia.mj.impl.gcf.utils.URI; |
|
32 import com.nokia.mj.impl.rt.support.Jvm; |
|
33 import com.nokia.mj.impl.utils.Logger; |
|
34 import com.nokia.mj.impl.gcf.utils.DateUtil; |
|
35 import com.nokia.mj.impl.gcf.utils.NativeError; |
|
36 import com.nokia.mj.impl.http.BlockingOperation; |
|
37 import com.nokia.mj.impl.rt.support.Finalizer; |
|
38 import com.nokia.mj.impl.connectionmanager.ConnectionManager; |
|
39 import com.nokia.mj.impl.connectionmanager.AccessPoint; |
|
40 import com.nokia.mj.impl.rt.support.ApplicationUtils; |
|
41 import com.nokia.mj.impl.rt.support.ApplicationInfo; |
|
42 import com.nokia.mj.impl.rt.support.ShutdownListener; |
|
43 |
|
44 /** |
|
45 * An HttpConection class implementing an HTTP 1.1 client connection using the |
|
46 * native symbian http client ap |
|
47 * |
|
48 */ |
|
49 public class HttpConnectionNative implements HttpConnection, |
|
50 NativeHttpByteSource |
|
51 { |
|
52 protected int iMode; |
|
53 protected int iState; |
|
54 protected boolean iClosed; |
|
55 protected URI iUri; |
|
56 protected String iRef; |
|
57 protected String iRequestMethod; |
|
58 protected Hashtable iRequestProperties; |
|
59 protected int iResponseCode; |
|
60 protected String iResponseMessage; |
|
61 protected Hashtable iReplyHeaders; |
|
62 protected Vector iReplyHeaderKeys; |
|
63 protected long iLength; |
|
64 protected DataInputStream iInputStream; |
|
65 protected boolean iInputStreamOpened = false; |
|
66 protected NativeHttpInputStream iNativeHttpInputStream; |
|
67 protected ByteArrayOutputStream iPostedDataStream; |
|
68 protected DataOutputStream iOutputStream; |
|
69 protected boolean iOutputStreamOpened = false; |
|
70 protected char[] iLineBuffer; |
|
71 protected int iLineBufferLength; |
|
72 protected int iLineLength; |
|
73 |
|
74 // States |
|
75 protected final static int INVALID_STATE = 0; |
|
76 protected final static int SETUP = 1; |
|
77 protected final static int CONNECTED = 2; |
|
78 protected final static int REQUEST_HEADERS_SENT = 3; |
|
79 protected final static int REQUEST_SENT = 4; |
|
80 protected final static int REPLY_RECEIVED = 5; |
|
81 |
|
82 // Character constants |
|
83 protected final static char HASH = '#'; |
|
84 protected final static int QUESTION_MARK = 63; |
|
85 protected final static int CR = 13; |
|
86 protected final static int LF = 10; |
|
87 protected final static int SP = 32; |
|
88 protected final static int EOF = -1; |
|
89 |
|
90 // Misc. Constants |
|
91 protected final static byte[] CRLF = { CR, LF }; |
|
92 protected final static int DEFAULT_LINE_BUFFER_SIZE = 128; |
|
93 protected final static String VERSION_1_1 = "1.1"; |
|
94 protected final static String VERSION_1_0 = "1.0"; |
|
95 protected final static String NATIVESEPERATOR = ";;"; |
|
96 protected final static String DEFAULT_PATH = "/"; // NOI8N |
|
97 protected final static int DEFAULT_PORT = 80; |
|
98 protected final static String PROTOCOL_SUFFIX = "://"; |
|
99 |
|
100 // 'Well-known' Header names |
|
101 protected final static String CONNECTION = "Connection"; // NOI8N |
|
102 protected final static String CONTENT_ENCODING = "Content-Encoding"; // NOI8N |
|
103 protected final static String CONTENT_LENGTH = "Content-Length"; // NOI8N |
|
104 protected final static String CONTENT_TYPE = "Content-Type"; // NOI8N |
|
105 protected final static String DATE = "Date"; // NOI8N |
|
106 protected final static String HOST = "Host"; // NOI8N |
|
107 protected final static String LAST_MODIFIED = "Last-Modified"; // NOI8N |
|
108 protected final static String EXPIRES = "Expires"; // NOI8N |
|
109 protected final static String TRANSFER_ENCODING = "Transfer-Encoding"; // NOI8N |
|
110 protected final static String USER_AGENT = "User-Agent"; |
|
111 |
|
112 // 'Well-known' Header values |
|
113 protected final static String UNTRUSTED_1_0 = "UNTRUSTED/1.0"; |
|
114 |
|
115 // Connection value |
|
116 protected final static String CLOSE = "close"; // NOI8N |
|
117 |
|
118 // Http-native handle |
|
119 private static int iNativeHttpSessionHandle = 0; |
|
120 |
|
121 protected int iNativeTransactionHande = 0; |
|
122 final BlockingOperation iTransactionBlock; |
|
123 |
|
124 // Custom lock for synchronizing all read operations. |
|
125 protected final BlockingOperation iNativeDataReadyForRead; |
|
126 |
|
127 private Finalizer iFinalizer; |
|
128 protected ConnectionManager iCmInstance = null; |
|
129 protected AccessPoint iApn = null; |
|
130 private static boolean iIsSessionDeleted = false; |
|
131 private boolean iTrustedSuite = true; |
|
132 private int iRespTimeOut = -1; |
|
133 private int iRetries = 0; |
|
134 |
|
135 static |
|
136 { |
|
137 try |
|
138 { |
|
139 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
140 "loading http from HttpConnectionNative.java"); |
|
141 Jvm.loadSystemLibrary("javahttp"); |
|
142 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "javahttp loaded"); |
|
143 } |
|
144 catch (Exception e) |
|
145 { |
|
146 Logger.ELOG(Logger.ESOCKET, e.toString()); |
|
147 } |
|
148 } |
|
149 |
|
150 public HttpConnectionNative(int aNativeHttpSessionHandle, String aName, |
|
151 int aMode, boolean aTimeouts, ConnectionManager cm, |
|
152 AccessPoint apnInfo, int aResponseTimeout) throws IOException |
|
153 { |
|
154 Logger.PLOG(Logger.ESOCKET, "New HTTP connection to URL: " + aName); |
|
155 Logger.ILOG(Logger.ESOCKET, "+++++ HttpConnectionNative new, this =" |
|
156 + this); |
|
157 |
|
158 int index; |
|
159 iCmInstance = cm; |
|
160 iApn = apnInfo; |
|
161 index = aName.indexOf(HASH); |
|
162 iRespTimeOut = aResponseTimeout; // setting of timeout value for http response. |
|
163 // specific scenario identified in case of java installer. |
|
164 |
|
165 // Handle to shared native RHttpSession |
|
166 if (iNativeHttpSessionHandle == 0) |
|
167 { |
|
168 // only one session per application |
|
169 creatHttpSession(); |
|
170 } |
|
171 |
|
172 if (index != -1) |
|
173 { |
|
174 iRef = aName.substring(index + 1); |
|
175 aName = aName.substring(0, index); |
|
176 } |
|
177 |
|
178 iUri = new URI(aName); |
|
179 final String host = iUri.getHost(); |
|
180 if (host == null || host.equals("")) |
|
181 { |
|
182 throw new IllegalArgumentException("Invalid url: " + aName); |
|
183 } |
|
184 |
|
185 iMode = aMode; |
|
186 iState = SETUP; |
|
187 iRequestMethod = GET; |
|
188 iRequestProperties = new Hashtable(); |
|
189 iReplyHeaders = new Hashtable(); |
|
190 iReplyHeaderKeys = new Vector(); |
|
191 iLength = -1; |
|
192 |
|
193 // Blocking operations to allow async native transactions |
|
194 iTransactionBlock = new BlockingOperation(); |
|
195 iNativeDataReadyForRead = new BlockingOperation(); |
|
196 iNativeDataReadyForRead.setResult(BlockingOperation.BLOCKED); |
|
197 iFinalizer = registerForFinalization(); |
|
198 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- HttpConnectionNative new "); |
|
199 |
|
200 ApplicationInfo appInfo = ApplicationInfo.getInstance(); |
|
201 String runtime = appInfo.getRuntimeType(); |
|
202 boolean midpRuntime = true; |
|
203 |
|
204 if (runtime == ApplicationInfo.RUNTIME_INSTALLER) |
|
205 { |
|
206 midpRuntime = false; |
|
207 } |
|
208 else |
|
209 { |
|
210 // add the untrusted header for untrusted midlet suite |
|
211 if ((ApplicationInfo.getInstance().getProtectionDomain() |
|
212 .equals(ApplicationInfo.UNIDENTIFIED_THIRD_PARTY_DOMAIN)) == true) |
|
213 { |
|
214 iTrustedSuite = false; |
|
215 iRequestProperties.put(USER_AGENT, UNTRUSTED_1_0); |
|
216 } |
|
217 } |
|
218 // get the default User-Agent headers and add to hashtable |
|
219 final String agent = _getUserAgentHeaderValue(midpRuntime); |
|
220 if (agent != null) |
|
221 { |
|
222 if (iTrustedSuite == false) |
|
223 { |
|
224 String result = agent + ' ' + UNTRUSTED_1_0; |
|
225 iRequestProperties.put(USER_AGENT, result); |
|
226 } |
|
227 else |
|
228 { |
|
229 iRequestProperties.put(USER_AGENT, agent); |
|
230 } |
|
231 } |
|
232 } |
|
233 |
|
234 Finalizer registerForFinalization() |
|
235 { |
|
236 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
237 "++HttpConnectionNative::registerForFinalization "); |
|
238 return new Finalizer() |
|
239 { |
|
240 public void finalizeImpl() |
|
241 { |
|
242 doFinalize(); |
|
243 } |
|
244 }; |
|
245 } |
|
246 |
|
247 |
|
248 public void doFinalize() |
|
249 { |
|
250 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
251 "++HttpConnectionNative::doFinalize "); |
|
252 try |
|
253 { |
|
254 close(); |
|
255 } |
|
256 catch(Exception e) |
|
257 { |
|
258 |
|
259 } |
|
260 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
261 "--HttpConnectionNative::doFinalize "); |
|
262 } |
|
263 |
|
264 public void creatHttpSession() throws IOException |
|
265 { |
|
266 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
267 "++HttpConnectionNative::creatHttpSession()"); |
|
268 int[] retval = new int[2]; |
|
269 int handle; |
|
270 int err; |
|
271 if (iApn != null) |
|
272 { |
|
273 handle = _createHttpSession(0, iApn.getType(), iApn.getNapId(), |
|
274 retval); |
|
275 } |
|
276 else |
|
277 { |
|
278 handle = _createHttpSession(0, -1, -1, retval); |
|
279 } |
|
280 iNativeHttpSessionHandle = NativeError.check(handle); |
|
281 if (retval[0] < 0) |
|
282 { |
|
283 throw new IOException( |
|
284 "Unable to open http connection.Creation of Native peer failed."); |
|
285 } |
|
286 if (retval[1] < 0) |
|
287 { |
|
288 // reset connection manager |
|
289 iCmInstance.reset(); |
|
290 } |
|
291 |
|
292 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
293 "--HttpConnectionNative::creatHttpSession()"); |
|
294 } |
|
295 |
|
296 /** |
|
297 * Please refer to Jsr 118 |
|
298 */ |
|
299 public synchronized void close() throws IOException |
|
300 { |
|
301 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "++++++++++ close()"); |
|
302 if (iClosed) |
|
303 { |
|
304 return; |
|
305 } |
|
306 iClosed = true; |
|
307 if ((iInputStream == null) && (iOutputStream == null) |
|
308 && (iState != SETUP)) |
|
309 { |
|
310 if (iNativeHttpInputStream != null) |
|
311 { |
|
312 iNativeHttpInputStream.close(); |
|
313 iNativeHttpInputStream = null; |
|
314 } |
|
315 closeConnection(); |
|
316 } |
|
317 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "------- close()"); |
|
318 return; |
|
319 } |
|
320 |
|
321 /** |
|
322 * Please refer to Jsr 118 |
|
323 */ |
|
324 public synchronized DataInputStream openDataInputStream() |
|
325 throws IOException |
|
326 { |
|
327 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openDataInputStream()"); |
|
328 // prevents multiple read |
|
329 synchronized (iNativeDataReadyForRead.getLock()) |
|
330 { |
|
331 ensureOpen("openDataInputStream"); |
|
332 if (iInputStreamOpened) |
|
333 { |
|
334 throwIOException("Input stream is already opened"); |
|
335 } |
|
336 ensureResponse(); |
|
337 iInputStream = makeDataInputStream(); |
|
338 iInputStreamOpened = true; |
|
339 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- |
|
340 // openDataInputStream()" ); |
|
341 return iInputStream; |
|
342 } |
|
343 } |
|
344 |
|
345 /** |
|
346 * Please refer to Jsr 118 |
|
347 */ |
|
348 public synchronized InputStream openInputStream() throws IOException |
|
349 { |
|
350 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openInputStream()" ); |
|
351 final InputStream result = openDataInputStream(); |
|
352 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- openInputStream()" ); |
|
353 return result; |
|
354 } |
|
355 |
|
356 |
|
357 /** |
|
358 * Please refer to Jsr 118 |
|
359 */ |
|
360 |
|
361 public synchronized DataOutputStream openDataOutputStream() |
|
362 throws IOException |
|
363 { |
|
364 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openDataOutputStream()" |
|
365 // ); |
|
366 ensureOpen("openDataOutputStream"); |
|
367 if (iOutputStreamOpened) |
|
368 { |
|
369 throwIOException("Output stream is already opened"); |
|
370 } |
|
371 makeDataOutputStream(); |
|
372 iOutputStreamOpened = true; |
|
373 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- openDataOutputStream()" |
|
374 // ); |
|
375 return iOutputStream; |
|
376 } |
|
377 |
|
378 /** |
|
379 * Please refer to Jsr 118 |
|
380 */ |
|
381 public synchronized OutputStream openOutputStream() throws IOException |
|
382 { |
|
383 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ openOutputStream()" ); |
|
384 final OutputStream result = openDataOutputStream(); |
|
385 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- openOutputStream()" ); |
|
386 return result; |
|
387 } |
|
388 |
|
389 /** |
|
390 * Please refer to Jsr 118 |
|
391 */ |
|
392 public synchronized String getEncoding() |
|
393 { |
|
394 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getEncoding()" ); |
|
395 String result = null; |
|
396 try |
|
397 { |
|
398 result = getHeaderField(CONTENT_ENCODING); |
|
399 } |
|
400 catch (IOException ex) |
|
401 { |
|
402 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getEncoding() returns |
|
403 // null" ); |
|
404 return null; |
|
405 } |
|
406 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getEncoding()" ); |
|
407 return result; |
|
408 } |
|
409 |
|
410 /** |
|
411 * Please refer to Jsr 118 |
|
412 */ |
|
413 public synchronized long getLength() |
|
414 { |
|
415 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getLength()"); |
|
416 try |
|
417 { |
|
418 ensureOpen("getLength"); |
|
419 ensureResponse(); |
|
420 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getLength() : " + |
|
421 // iLength); |
|
422 return iLength; |
|
423 } |
|
424 catch (IOException ex) |
|
425 { |
|
426 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getLength() set -1 |
|
427 // IOException: "+ ex.toString() ); |
|
428 return -1; |
|
429 } |
|
430 } |
|
431 |
|
432 /** |
|
433 * Please refer to Jsr 118 |
|
434 */ |
|
435 public synchronized String getType() |
|
436 { |
|
437 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getType()" ); |
|
438 String result = null; |
|
439 try |
|
440 { |
|
441 result = getHeaderField(CONTENT_TYPE); |
|
442 } |
|
443 catch (IOException ex) |
|
444 { |
|
445 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getType() returns |
|
446 // null" ); |
|
447 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getType() NULL"); |
|
448 return null; |
|
449 } |
|
450 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getType()" + result); |
|
451 return result; |
|
452 } |
|
453 |
|
454 // HttpConnection interface implementation |
|
455 |
|
456 public synchronized long getDate() throws IOException |
|
457 { |
|
458 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getDate()" ); |
|
459 final long result = getHeaderFieldDate(DATE, 0); |
|
460 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getDate()" ); |
|
461 return result; |
|
462 } |
|
463 |
|
464 public synchronized long getExpiration() throws IOException |
|
465 { |
|
466 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getExpiration()" ); |
|
467 final long result = getHeaderFieldDate(EXPIRES, 0); |
|
468 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getExpiration()" ); |
|
469 return result; |
|
470 } |
|
471 |
|
472 public String getFile() |
|
473 { |
|
474 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getFile()" ); |
|
475 String result = iUri.getPath(); |
|
476 if (result.length() == 0) |
|
477 result = null; |
|
478 else |
|
479 result = "/" + result; |
|
480 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getFile: " + result ); |
|
481 return result; |
|
482 } |
|
483 |
|
484 public synchronized String getHeaderField(int aIndex) throws IOException |
|
485 { |
|
486 ensureOpen("getHeaderField"); |
|
487 ensureResponse(); |
|
488 if (aIndex >= iReplyHeaderKeys.size() || aIndex < 0) |
|
489 { |
|
490 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderField(int) |
|
491 // returns null" ); |
|
492 return null; |
|
493 } |
|
494 final String result = (String) iReplyHeaders.get(iReplyHeaderKeys |
|
495 .elementAt(aIndex)); |
|
496 if (result != null) |
|
497 { |
|
498 int length = result.length(); |
|
499 String keys = (String) iReplyHeaderKeys.elementAt(aIndex); |
|
500 if (keys.equalsIgnoreCase("Set-Cookie") == true) |
|
501 { |
|
502 // first cookie is discarded |
|
503 if ((result.charAt(0)) == ',') |
|
504 { |
|
505 throw new IOException( |
|
506 "cookie size too large - hence discarded"); |
|
507 } |
|
508 |
|
509 // last cookie is discarded |
|
510 if ((result.charAt(length - 2)) == ',') |
|
511 { |
|
512 throw new IOException( |
|
513 "cookie size too large - hence discarded"); |
|
514 } |
|
515 |
|
516 int index = result.indexOf(", ,", 0); |
|
517 if (index != -1) |
|
518 { |
|
519 throw new IOException( |
|
520 "cookie size too large - hence discarded"); |
|
521 } |
|
522 } |
|
523 } |
|
524 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderField(int)" ); |
|
525 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHeaderField(int): " + result); |
|
526 return result; |
|
527 } |
|
528 |
|
529 public synchronized String getHeaderField(String aName) throws IOException |
|
530 { |
|
531 ensureOpen("getHeaderField"); |
|
532 ensureResponse(); |
|
533 if (aName == null) |
|
534 { |
|
535 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-- |
|
536 // getHeaderField(String) returns null" ); |
|
537 return null; |
|
538 } |
|
539 final String result = (String) iReplyHeaders.get(aName.toLowerCase()); |
|
540 |
|
541 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHeaderField(String): " |
|
542 + result); |
|
543 if (result != null) |
|
544 { |
|
545 int length = result.length(); |
|
546 if (aName.equalsIgnoreCase("Set-Cookie") == true) |
|
547 { |
|
548 // first cookie is discarded |
|
549 if ((result.charAt(0)) == ',') |
|
550 { |
|
551 throw new IOException( |
|
552 "cookie size too large - hence discarded"); |
|
553 } |
|
554 |
|
555 // last cookie is discarded |
|
556 if ((result.charAt(length - 2)) == ',') |
|
557 { |
|
558 throw new IOException( |
|
559 "cookie size too large - hence discarded"); |
|
560 } |
|
561 |
|
562 int index = result.indexOf(", ,", 0); |
|
563 if (index != -1) |
|
564 { |
|
565 throw new IOException( |
|
566 "cookie size too large - hence discarded"); |
|
567 } |
|
568 } |
|
569 } |
|
570 return result; |
|
571 } |
|
572 |
|
573 public synchronized long getHeaderFieldDate(String aName, long aDfault) |
|
574 throws IOException |
|
575 { |
|
576 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
577 "+ getHeaderFieldDate(String, long)"); |
|
578 String value; |
|
579 |
|
580 value = getHeaderField(aName); |
|
581 if (value != null) |
|
582 { |
|
583 final long result = parseDate(value); |
|
584 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
585 "- getHeaderFieldDate(String, long)"); |
|
586 return result; |
|
587 } |
|
588 else |
|
589 { |
|
590 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
591 "- getHeaderFieldDate(String, long) return aDfault"); |
|
592 return aDfault; |
|
593 } |
|
594 } |
|
595 |
|
596 public synchronized int getHeaderFieldInt(String aName, int aDfault) |
|
597 throws IOException |
|
598 { |
|
599 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
600 "+ getHeaderFieldInt(String, int) , name = " + aName |
|
601 + "default = " + aDfault); |
|
602 String value; |
|
603 |
|
604 value = getHeaderField(aName); |
|
605 if (value == null) |
|
606 { |
|
607 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
608 "- getHeaderFieldInt(String, int) returns aDfault"); |
|
609 return aDfault; |
|
610 } |
|
611 else |
|
612 { |
|
613 try |
|
614 { |
|
615 final int result = Integer.parseInt(value); |
|
616 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- |
|
617 // getHeaderFieldInt(String, int)" ); |
|
618 return result; |
|
619 } |
|
620 catch (NumberFormatException nfe) |
|
621 { |
|
622 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderFieldInt (String, int): " + aDfault); |
|
623 return aDfault; |
|
624 } |
|
625 } |
|
626 } |
|
627 |
|
628 public synchronized String getHeaderFieldKey(int aIndex) throws IOException |
|
629 { |
|
630 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHeaderFieldKey(int)" |
|
631 // ); |
|
632 ensureOpen("getHeaderFieldKey"); |
|
633 ensureResponse(); |
|
634 if (aIndex >= iReplyHeaderKeys.size() || aIndex < 0) |
|
635 { |
|
636 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- |
|
637 // getHeaderFieldKey(int) returns null" ); |
|
638 return null; |
|
639 } |
|
640 final String result = (String) iReplyHeaderKeys.elementAt(aIndex); |
|
641 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHeaderFieldKey(int)" |
|
642 // ); |
|
643 return result; |
|
644 } |
|
645 |
|
646 public String getHost() |
|
647 { |
|
648 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getHost()" ); |
|
649 final String result = iUri.getHost(); |
|
650 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getHost()" ); |
|
651 return result; |
|
652 } |
|
653 |
|
654 public synchronized long getLastModified() throws IOException |
|
655 { |
|
656 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getLastModified()" ); |
|
657 final long result = getHeaderFieldDate(LAST_MODIFIED, 0); |
|
658 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getLastModified()" ); |
|
659 return result; |
|
660 } |
|
661 |
|
662 public int getPort() |
|
663 { |
|
664 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getPort()" ); |
|
665 final String temp = iUri.getPort(); |
|
666 if (temp.length() != 0) |
|
667 { |
|
668 try |
|
669 { |
|
670 final int result = Integer.parseInt(temp); |
|
671 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getPort()" ); |
|
672 return result; |
|
673 } |
|
674 catch (NumberFormatException ex) |
|
675 { |
|
676 // do nothing, return default port |
|
677 } |
|
678 } |
|
679 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getPort() returns default port" ); |
|
680 return DEFAULT_PORT; |
|
681 } |
|
682 |
|
683 public String getProtocol() |
|
684 { |
|
685 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getProtocol()" ); |
|
686 final String result = iUri.getProtocol(); |
|
687 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getProtocol()" ); |
|
688 return result; |
|
689 } |
|
690 |
|
691 public String getQuery() |
|
692 { |
|
693 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getQuery()" ); |
|
694 String result = iUri.getQuery(); |
|
695 if (result.length() == 0) |
|
696 result = null; |
|
697 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getQuery()" ); |
|
698 return result; |
|
699 } |
|
700 |
|
701 public String getRef() |
|
702 { |
|
703 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "* getRef()" ); |
|
704 return iRef; |
|
705 } |
|
706 |
|
707 public final String getRequestMethod() |
|
708 { |
|
709 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "* getRequestMethod()" ); |
|
710 return iRequestMethod; |
|
711 } |
|
712 |
|
713 public final String getRequestProperty(String aKey) |
|
714 { |
|
715 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ |
|
716 // getRequestProperty(String)" ); |
|
717 final String result = (String) iRequestProperties.get(aKey); |
|
718 |
|
719 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- |
|
720 // getRequestProperty(String)" ); |
|
721 return result; |
|
722 } |
|
723 |
|
724 public synchronized final int getResponseCode() throws IOException |
|
725 { |
|
726 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getResponseCode()"); |
|
727 ensureOpen("getResponseCode"); |
|
728 ensureResponse(); |
|
729 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getResponseCode() : " |
|
730 + iResponseCode); |
|
731 return iResponseCode; |
|
732 } |
|
733 |
|
734 public synchronized String getResponseMessage() throws IOException |
|
735 { |
|
736 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getResponseMessage()" ); |
|
737 ensureOpen("getResponseMessage"); |
|
738 ensureResponse(); |
|
739 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getResponseMessage() : " |
|
740 // + iResponseMessage); |
|
741 return iResponseMessage; |
|
742 } |
|
743 |
|
744 public String getURL() |
|
745 { |
|
746 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getURL()" ); |
|
747 final String result = iUri.toString(); |
|
748 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getURL()" ); |
|
749 return result; |
|
750 } |
|
751 |
|
752 /** |
|
753 * Please refer to Jsr 118 |
|
754 */ |
|
755 public synchronized void setRequestMethod(String aMethod) |
|
756 throws IOException |
|
757 { |
|
758 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ setRequestMethod(String)" |
|
759 // ); |
|
760 try |
|
761 { |
|
762 if (aMethod == null) |
|
763 { |
|
764 throw new NullPointerException("Request method is null"); |
|
765 } |
|
766 ensureOpen("setRequestMethod"); |
|
767 if (iState != SETUP) |
|
768 { |
|
769 throwIOException("setRequestMethod method failed.Connection state is already connected"); |
|
770 } |
|
771 if ((GET.equals(aMethod) == false) |
|
772 && (HEAD.equals(aMethod) == false) |
|
773 && (POST.equals(aMethod) == false)) |
|
774 { |
|
775 throwIOException("Invalid or Unsupported request method: " |
|
776 + aMethod); |
|
777 } |
|
778 // ignore if an output stream has already been open |
|
779 if (iPostedDataStream == null) |
|
780 iRequestMethod = aMethod; |
|
781 } |
|
782 catch (IOException ex) |
|
783 { |
|
784 Logger.WLOG(Logger.ESOCKET, "setRequestMethod failed", ex); |
|
785 throw ex; |
|
786 } |
|
787 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- setRequestMethod(String)" ); |
|
788 return; |
|
789 } |
|
790 |
|
791 /** |
|
792 * Please refer to Jsr 118 |
|
793 */ |
|
794 public synchronized void setRequestProperty(String aKey, String aValue) |
|
795 throws IOException |
|
796 { |
|
797 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ setRequestProperty( " + |
|
798 // aKey + " , " + aValue ); |
|
799 ensureOpen("setRequestProperty"); |
|
800 if (iState != SETUP) |
|
801 { |
|
802 throwIOException("setRequestProperty method failed.Connection state is already connected"); |
|
803 } |
|
804 |
|
805 // ignore if an outputstream has been open |
|
806 if (iPostedDataStream == null) |
|
807 { |
|
808 if (aKey.equals(USER_AGENT) && !iTrustedSuite) |
|
809 { |
|
810 String val = aValue + ' ' + UNTRUSTED_1_0; |
|
811 iRequestProperties.put(aKey, val); |
|
812 } |
|
813 else |
|
814 { |
|
815 iRequestProperties.put(aKey, aValue); |
|
816 } |
|
817 } |
|
818 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- setRequestProperty(String, String)" ); |
|
819 return; |
|
820 } |
|
821 |
|
822 protected void closeConnection() throws IOException |
|
823 { |
|
824 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
825 "++++++++++++++ Java closeConnection()"); |
|
826 if ((iNativeTransactionHande != 0) &&(iNativeHttpSessionHandle!=0)) |
|
827 { |
|
828 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "########## Valid handle"); |
|
829 _closeTransaction(iNativeTransactionHande); |
|
830 iNativeTransactionHande = 0; |
|
831 |
|
832 } |
|
833 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
834 "-------------- Java closeConnection()"); |
|
835 } |
|
836 |
|
837 protected void addHeader(String aKey, String aValue) |
|
838 { |
|
839 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ addHeader to reply enum( |
|
840 // " + aKey + " , " + aValue ); |
|
841 // Should check for duplicate keys |
|
842 aKey = aKey.toLowerCase(); |
|
843 iReplyHeaders.put(aKey, aValue); |
|
844 iReplyHeaderKeys.addElement(aKey); |
|
845 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- addHeader(String, |
|
846 // String)" ); |
|
847 return; |
|
848 } |
|
849 |
|
850 protected synchronized void inputStreamClosed() throws IOException |
|
851 { |
|
852 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "++++++ inputStreamClosed()"); |
|
853 synchronized (iNativeDataReadyForRead.getLock()) |
|
854 { |
|
855 iInputStream = null; |
|
856 iNativeHttpInputStream = null; |
|
857 if (iClosed && (iOutputStream == null)) |
|
858 { |
|
859 closeConnection(); |
|
860 } |
|
861 } |
|
862 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
863 "-------- inputStreamClosed()"); |
|
864 } |
|
865 |
|
866 |
|
867 protected synchronized void outputStreamFlushed() throws IOException |
|
868 { |
|
869 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ outputStreamFlushed()" ); |
|
870 switch (iState) |
|
871 { |
|
872 case SETUP: |
|
873 case CONNECTED: |
|
874 case REQUEST_HEADERS_SENT: |
|
875 ensureResponse(); |
|
876 |
|
877 default: |
|
878 // No-op |
|
879 ; |
|
880 } |
|
881 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- outputStreamFlushed()" ); |
|
882 } |
|
883 |
|
884 protected synchronized void outputStreamClosed() throws IOException |
|
885 { |
|
886 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
887 "++++++++ outputStreamClosed()"); |
|
888 iOutputStream = null; |
|
889 iPostedDataStream = null; |
|
890 if (iClosed && iInputStream == null) |
|
891 { |
|
892 closeConnection(); |
|
893 } |
|
894 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
895 "-------- outputStreamClosed()"); |
|
896 } |
|
897 |
|
898 private synchronized void connect() throws IOException |
|
899 { |
|
900 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+++++++ Java connect()"); |
|
901 if (iNativeTransactionHande <= 0) |
|
902 { |
|
903 final int handle = _createNativeTransaction( |
|
904 iNativeHttpSessionHandle, iUri.toString(), iRequestMethod); |
|
905 iNativeTransactionHande = NativeError.check(handle); |
|
906 } |
|
907 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-------- connect()"); |
|
908 } |
|
909 |
|
910 protected void ensureConnected() throws IOException |
|
911 { |
|
912 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureConnected()" ); |
|
913 switch (iState) |
|
914 { |
|
915 case SETUP: |
|
916 |
|
917 connect(); |
|
918 iState = CONNECTED; |
|
919 break; |
|
920 |
|
921 default: |
|
922 ; |
|
923 } |
|
924 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureConnected()" ); |
|
925 return; |
|
926 } |
|
927 |
|
928 protected void ensureOpen(String aMethodName) throws IOException |
|
929 { |
|
930 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureOpen()" ); |
|
931 if (iClosed) |
|
932 { |
|
933 throwIOException(aMethodName |
|
934 + " method failed.Connection state is already closed"); |
|
935 } |
|
936 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureOpen()" ); |
|
937 return; |
|
938 } |
|
939 |
|
940 protected void ensureResponse() throws IOException |
|
941 { |
|
942 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureResponse()" ); |
|
943 ensureConnected(); |
|
944 switch (iState) |
|
945 { |
|
946 case CONNECTED: |
|
947 |
|
948 sendRequest(); |
|
949 // Fall Through |
|
950 case REQUEST_HEADERS_SENT: |
|
951 case REQUEST_SENT: |
|
952 getResponse(); |
|
953 iState = REPLY_RECEIVED; |
|
954 break; |
|
955 |
|
956 default: |
|
957 // No-op |
|
958 ; |
|
959 } |
|
960 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureResponse()" ); |
|
961 return; |
|
962 } |
|
963 |
|
964 protected synchronized void getResponse() throws IOException |
|
965 { |
|
966 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ getResponse()"); |
|
967 |
|
968 boolean flag = true; |
|
969 String[] rawHeaders = _getResponse(iNativeTransactionHande); |
|
970 if (rawHeaders == null || rawHeaders.length == 0) |
|
971 throwIOException("Invalid http response"); |
|
972 |
|
973 // First element is the Status Line |
|
974 readStatusLine(rawHeaders[0]); |
|
975 readHeaders(rawHeaders); |
|
976 processReplyHeaders(); |
|
977 rawHeaders = null; |
|
978 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- getResponse()" ); |
|
979 return; |
|
980 } |
|
981 |
|
982 protected void readStatusLine(String aStatusLine) throws IOException |
|
983 { |
|
984 // Status-Line = HTTP-Version ;; Status-Code ;; Reason-Phrase |
|
985 Logger.PLOG(Logger.ESOCKET, "HTTP response, status line: " |
|
986 + aStatusLine); |
|
987 // HTTP-Version |
|
988 final int fisrtSepIndex = aStatusLine.indexOf(NATIVESEPERATOR); |
|
989 if (fisrtSepIndex <= 0) |
|
990 { |
|
991 throwIOException("Invalid http response"); |
|
992 } |
|
993 String parse = aStatusLine.substring(0, fisrtSepIndex); |
|
994 |
|
995 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, " Server Vesion : " + parse |
|
996 // ); |
|
997 |
|
998 // Check the server we are connecting to is a http v1.0 or v1.1 |
|
999 if (parse.compareTo(VERSION_1_1) != 0 |
|
1000 && parse.compareTo(VERSION_1_0) != 0) |
|
1001 { |
|
1002 throwIOException("Invalid http response.Http-version mismatch"); |
|
1003 } |
|
1004 |
|
1005 // Status Code |
|
1006 int nextSepIndex = 0; |
|
1007 nextSepIndex = aStatusLine.indexOf(NATIVESEPERATOR, fisrtSepIndex + 2); |
|
1008 if (nextSepIndex <= 0) |
|
1009 { |
|
1010 throwIOException("Invalid http response"); |
|
1011 } |
|
1012 parse = null; |
|
1013 parse = aStatusLine.substring(fisrtSepIndex + 2, nextSepIndex); |
|
1014 iResponseCode = Integer.parseInt(parse); |
|
1015 |
|
1016 // Reason-Phrase |
|
1017 |
|
1018 iResponseMessage = aStatusLine.substring(nextSepIndex + 2, aStatusLine |
|
1019 .length()); |
|
1020 if (iResponseMessage.length() <= 0) |
|
1021 { |
|
1022 throwIOException("Invalid http response"); |
|
1023 } |
|
1024 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- readStatusLine(InputStream)" ); |
|
1025 } |
|
1026 |
|
1027 protected long parseDate(String aDateString) |
|
1028 { |
|
1029 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ parseDate(String)" ); |
|
1030 final long result = DateUtil.epocDifference(aDateString); |
|
1031 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- parseDate(String)" ); |
|
1032 return result; |
|
1033 } |
|
1034 |
|
1035 protected void processReplyHeaders() |
|
1036 { |
|
1037 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ processReplyHeaders()" ); |
|
1038 String value; |
|
1039 value = (String) iReplyHeaders.get(CONTENT_LENGTH.toLowerCase()); |
|
1040 if (value != null) |
|
1041 { |
|
1042 iLength = Long.parseLong(value); |
|
1043 } |
|
1044 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- processReplyHeaders()" ); |
|
1045 } |
|
1046 |
|
1047 protected void readHeaders(String[] aHeaders) throws IOException |
|
1048 { |
|
1049 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ readHeaders()" ); |
|
1050 // Headers are of the form |
|
1051 // valueKey + NATIVESEPERATOR + property |
|
1052 String key; |
|
1053 String value; |
|
1054 String rawHeader = null; |
|
1055 final int headersCount = aHeaders.length; |
|
1056 |
|
1057 // First element is status line which we ignore (parsed in |
|
1058 // readStatusLine) |
|
1059 int sepIndex = -1; |
|
1060 for (int ii = 1; ii < headersCount; ++ii) |
|
1061 { |
|
1062 rawHeader = aHeaders[ii]; |
|
1063 sepIndex = rawHeader.indexOf(NATIVESEPERATOR); |
|
1064 key = rawHeader.substring(0, sepIndex); |
|
1065 value = rawHeader.substring(sepIndex + 2, rawHeader.length()); |
|
1066 addHeader(key, value); |
|
1067 rawHeader = null; |
|
1068 key = null; |
|
1069 value = null; |
|
1070 sepIndex = -1; |
|
1071 } |
|
1072 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- readHeaders(InputStream)" ); |
|
1073 } |
|
1074 |
|
1075 protected synchronized void sendRequest() throws IOException |
|
1076 { |
|
1077 ensureConnected(); |
|
1078 final int count = iRequestProperties.size(); |
|
1079 int headerCount = count; |
|
1080 |
|
1081 final Enumeration keyEnum = iRequestProperties.keys(); |
|
1082 String[] headers = null; |
|
1083 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- headerCount: " + |
|
1084 // headerCount ); |
|
1085 if (headerCount > 0) |
|
1086 headers = new String[headerCount]; |
|
1087 |
|
1088 String valueKey = null; |
|
1089 String property = null; |
|
1090 String concat = null; |
|
1091 boolean untrustedAdded = false; |
|
1092 for (int ii = 0; ii < count; ++ii) |
|
1093 { |
|
1094 valueKey = (String) keyEnum.nextElement(); |
|
1095 property = getRequestProperty(valueKey); |
|
1096 concat = valueKey + NATIVESEPERATOR + property; |
|
1097 headers[ii] = concat; |
|
1098 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "submit : " + ii + " : " |
|
1099 // + concat + "concat length:" + concat.length() ); |
|
1100 } |
|
1101 |
|
1102 byte[] postData = null; |
|
1103 int postDataLength = 0; |
|
1104 // Data to be sent native |
|
1105 if (iPostedDataStream != null) |
|
1106 { |
|
1107 postData = iPostedDataStream.toByteArray(); |
|
1108 postDataLength = postData.length; |
|
1109 } |
|
1110 |
|
1111 synchronized (iTransactionBlock.getLock()) |
|
1112 { |
|
1113 // Submit the headers and the data at the same time |
|
1114 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ _submitTransaction |
|
1115 // headers count : " + (headers!=null ?headers.length:-1 ) ); |
|
1116 synchronized (iTransactionBlock) |
|
1117 { |
|
1118 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1119 "before _submitTransaction "); |
|
1120 final int err = _submitTransaction(iNativeTransactionHande, |
|
1121 headers, postData, postDataLength,iRespTimeOut); |
|
1122 |
|
1123 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1124 "-_submitTransaction +err " + err); |
|
1125 |
|
1126 // Clear tempory byte array and headers array |
|
1127 postData = null; |
|
1128 headers = null; |
|
1129 if (err != 0) |
|
1130 throwIOException("Unable to connect to server.Symbian os error code: " |
|
1131 + err); |
|
1132 iState = REQUEST_SENT; |
|
1133 waitForTransaction(); |
|
1134 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1135 "- sendRequest _submitTransaction"); |
|
1136 } |
|
1137 } |
|
1138 if ((iTransactionBlock.getResult() == -18) &&(iRetries < 2)) |
|
1139 { |
|
1140 iRetries++; |
|
1141 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1142 "- sendRequest KErrNotReady erroi, calling recursive sendRequest()"); |
|
1143 sendRequest(); |
|
1144 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1145 "- sendRequest KErrNotReady erroi, calling recursive sendRequest() returned"); |
|
1146 } |
|
1147 } |
|
1148 |
|
1149 protected void throwIOException(String aMessage) throws IOException |
|
1150 { |
|
1151 throw new IOException(aMessage); |
|
1152 } |
|
1153 |
|
1154 protected void waitForTransaction() throws IOException |
|
1155 { |
|
1156 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+waitForTransaction"); |
|
1157 |
|
1158 iTransactionBlock.waitForCompletion(); |
|
1159 final int result = iTransactionBlock.getResult(); |
|
1160 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "waitForTransaction result :" |
|
1161 + result); |
|
1162 if ((result < 0)) |
|
1163 { |
|
1164 final Integer error = new Integer(result); |
|
1165 if ((result == -18)) |
|
1166 { |
|
1167 if (iRetries >=2) |
|
1168 { |
|
1169 throwIOException(error.toString()); |
|
1170 } |
|
1171 } |
|
1172 else |
|
1173 { |
|
1174 throwIOException(error.toString()); |
|
1175 } |
|
1176 |
|
1177 } |
|
1178 |
|
1179 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-waitForTransaction"); |
|
1180 } |
|
1181 |
|
1182 protected DataInputStream makeDataInputStream() throws IOException |
|
1183 { |
|
1184 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1185 ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> makeDataInputStream()<<<<<<<<<<<<<<<<<<<<<<<"); |
|
1186 DataInputStream result = null; |
|
1187 final String transferEncoding; |
|
1188 |
|
1189 final int bytesTotal = (int) getLength(); |
|
1190 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1191 "++++++ makeDataInputStream() getLength():" + bytesTotal); |
|
1192 |
|
1193 if (iNativeHttpInputStream == null) |
|
1194 iNativeHttpInputStream = new NativeHttpInputStream(this); |
|
1195 result = new PlainDataInputStream(iNativeHttpInputStream); |
|
1196 Logger.LOG(Logger.ESOCKET, Logger.EInfo, " makeDataInputStream()"); |
|
1197 return result; |
|
1198 } |
|
1199 |
|
1200 protected void makeDataOutputStream() throws IOException |
|
1201 { |
|
1202 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ makeDataOutputStream()" |
|
1203 // ); |
|
1204 iPostedDataStream = new ByteArrayOutputStream(); |
|
1205 iOutputStream = new PlainDataOutputStream(iPostedDataStream); |
|
1206 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- makeDataOutputStream()" |
|
1207 // ); |
|
1208 } |
|
1209 |
|
1210 /** |
|
1211 * From NativeHttpByteSoure |
|
1212 */ |
|
1213 public void closeByteSource() |
|
1214 { |
|
1215 } |
|
1216 |
|
1217 /* |
|
1218 * Returns the total number of bytes read into the buffer, or -1 if there is |
|
1219 * no more data because the end of the stream has been reached. |
|
1220 */ |
|
1221 public synchronized int getBytes(byte[] aBytes, int aLength) |
|
1222 throws IOException |
|
1223 { |
|
1224 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+getBytes()"); |
|
1225 int result = -1; |
|
1226 |
|
1227 // Prevents multiple read |
|
1228 synchronized (iNativeDataReadyForRead.getLock()) |
|
1229 { |
|
1230 synchronized (iNativeDataReadyForRead) |
|
1231 { |
|
1232 if (iNativeDataReadyForRead.getResult() == BlockingOperation.BLOCKED) |
|
1233 { |
|
1234 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1235 "+ getBytes()- ReadOperation.waitForCompletion()"); |
|
1236 iNativeDataReadyForRead.waitForCompletion(); |
|
1237 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1238 "- getBytes()- ReadOperation.waitForCompletion()"); |
|
1239 } |
|
1240 } |
|
1241 |
|
1242 final int callBackResult = iNativeDataReadyForRead.getResult(); |
|
1243 if (callBackResult == EOF) |
|
1244 return 0; // All data has been read |
|
1245 if (callBackResult < 0) |
|
1246 throwIOException("Unable to read http response.Symbian os error code: " |
|
1247 + result); |
|
1248 // Block until data has been read from native |
|
1249 iNativeDataReadyForRead.setResult(BlockingOperation.BLOCKED); |
|
1250 if (iNativeHttpSessionHandle!=0) |
|
1251 { |
|
1252 result = _getBytes(iNativeTransactionHande, aBytes, aLength); |
|
1253 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ 2 getBytes()- result " |
|
1254 + result); |
|
1255 } |
|
1256 } |
|
1257 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-getBytes() + result " |
|
1258 + result); |
|
1259 return result; |
|
1260 } |
|
1261 |
|
1262 public int available() throws IOException |
|
1263 { |
|
1264 if ((iClosed == true) && (iInputStream == null) |
|
1265 && (iOutputStream == null)) |
|
1266 { |
|
1267 throw new IOException( |
|
1268 "Available method failed.Connection is already closed"); |
|
1269 } |
|
1270 return _available(iNativeTransactionHande); |
|
1271 } |
|
1272 |
|
1273 /* |
|
1274 * Native call back methods |
|
1275 */ |
|
1276 protected void transactionSubmitCallback(int aStatus) |
|
1277 { |
|
1278 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1279 "+ transactionSubmitCallback Callback"); |
|
1280 iTransactionBlock.notifyCompleted(aStatus); |
|
1281 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1282 "- transactionSubmitCallback Callback"); |
|
1283 } |
|
1284 |
|
1285 protected void dataReadyForReadCallBack(int aStatus) |
|
1286 { |
|
1287 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ dataReadyForReadCallBack " |
|
1288 + aStatus); |
|
1289 iNativeDataReadyForRead.notifyCompleted(aStatus); |
|
1290 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- dataReadyForReadCallBack"); |
|
1291 } |
|
1292 |
|
1293 /* |
|
1294 * Native Calls |
|
1295 */ |
|
1296 private native int _createHttpSession(int a, int aType, int aApn, |
|
1297 int[] retval); |
|
1298 private native int _createNativeTransaction(int aNativeHttpSessionHandle, |
|
1299 String aUri, String aRequestMethod); |
|
1300 private native int _submitTransaction(int aNativeTransactionHande, |
|
1301 String[] aHeaders, byte[] aPostData, int aPostLength, |
|
1302 int aRespTimeOut); |
|
1303 private native String[] _getResponse(int aNativeTransactionHande); |
|
1304 private native int _getBytes(int aNativeTransactionHande, byte[] aBuffer, |
|
1305 int aLength); |
|
1306 private native void _closeTransaction(int aNativeTransactionHande); |
|
1307 private native int _available(int aNativeTransactionHande); |
|
1308 private native String _getUserAgentHeaderValue(boolean aMidpRuntime); |
|
1309 |
|
1310 /* |
|
1311 * |
|
1312 * class PlainDataInputStream |
|
1313 * |
|
1314 */ |
|
1315 protected class PlainDataInputStream extends DataInputStream |
|
1316 { |
|
1317 public void close() throws IOException |
|
1318 { |
|
1319 super.close(); |
|
1320 inputStreamClosed(); |
|
1321 } |
|
1322 |
|
1323 PlainDataInputStream(InputStream aIs) |
|
1324 { |
|
1325 super(aIs); |
|
1326 } |
|
1327 } |
|
1328 |
|
1329 /* |
|
1330 * |
|
1331 * class PlainDataOutputStream |
|
1332 * |
|
1333 */ |
|
1334 protected class PlainDataOutputStream extends DataOutputStream |
|
1335 { |
|
1336 private boolean iFlushed = false; |
|
1337 |
|
1338 public void close() throws IOException |
|
1339 { |
|
1340 if (!iFlushed) |
|
1341 flush(); |
|
1342 super.close(); |
|
1343 outputStreamClosed(); |
|
1344 } |
|
1345 |
|
1346 public void flush() throws IOException |
|
1347 { |
|
1348 super.flush(); |
|
1349 outputStreamFlushed(); |
|
1350 iFlushed = true; |
|
1351 } |
|
1352 |
|
1353 PlainDataOutputStream(OutputStream aOs) |
|
1354 { |
|
1355 super(aOs); |
|
1356 } |
|
1357 } |
|
1358 |
|
1359 class NativeHttpInputStream extends InputStream |
|
1360 { |
|
1361 private NativeHttpByteSource iByteSource; |
|
1362 private byte[] iBuffer; |
|
1363 private int iOffset; |
|
1364 private int iLength; |
|
1365 // 6K buffer to read from native http |
|
1366 private final static int BUFFER_SIZE = 6144; |
|
1367 private boolean iIsClosed; |
|
1368 |
|
1369 NativeHttpInputStream(NativeHttpByteSource aByteSource) |
|
1370 { |
|
1371 // Bytesource length may be -1 indicating CHUNKED (size unknown) |
|
1372 iByteSource = aByteSource; |
|
1373 iBuffer = new byte[BUFFER_SIZE]; |
|
1374 iIsClosed = false; |
|
1375 } |
|
1376 |
|
1377 public synchronized void close() throws IOException |
|
1378 { |
|
1379 iIsClosed = true; |
|
1380 iByteSource.closeByteSource(); |
|
1381 } |
|
1382 |
|
1383 public synchronized int read() throws IOException |
|
1384 { |
|
1385 final int BYTEPADDER = 0xFF; |
|
1386 // Logger.LOG(Logger.ESOCKET, Logger.EInfo,"NativeInputStream.read() |
|
1387 // iOffset, "+ iOffset + "iLength " + iLength); |
|
1388 throwIfClosed(); |
|
1389 |
|
1390 if (iOffset == iLength) |
|
1391 { |
|
1392 // Logger.LOG(Logger.ESOCKET, |
|
1393 // Logger.EInfo,"NativeInputStream.read() iOffset == iLength |
|
1394 // getBytes: iLength " + iLength ); |
|
1395 getBytes(); |
|
1396 } |
|
1397 |
|
1398 // Logger.LOG(Logger.ESOCKET, Logger.EInfo,"NativeInputStream.read() |
|
1399 // 2 iOffset, "+ iOffset + " iLength " + iLength); |
|
1400 if (iLength > 0) |
|
1401 { |
|
1402 return iBuffer[iOffset++] & BYTEPADDER; |
|
1403 } |
|
1404 else |
|
1405 { |
|
1406 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1407 "NativeInputStream.read(): return -1 "); |
|
1408 return EOF; |
|
1409 } |
|
1410 } |
|
1411 |
|
1412 public synchronized int read(byte[] aBytes, int aOffset, int aLength) |
|
1413 throws IOException |
|
1414 { |
|
1415 // Logger.LOG(Logger.ESOCKET, |
|
1416 // Logger.EInfo,"+NativeInputStream.read(,,,) aOffset, "+ aOffset + |
|
1417 // "aLength" + aLength); |
|
1418 |
|
1419 throwIfClosed(); |
|
1420 |
|
1421 int nBytes = 0; |
|
1422 while (nBytes < aLength) |
|
1423 { |
|
1424 // Logger.LOG(Logger.ESOCKET, |
|
1425 // Logger.EInfo,"NativeInputStream.read(,,,) nBytes, "+ nBytes); |
|
1426 int count = readInner(aBytes, aOffset + nBytes, aLength |
|
1427 - nBytes); |
|
1428 // Logger.LOG(Logger.ESOCKET, |
|
1429 // Logger.EInfo,"NativeInputStream.read(,,,) count = readInner, |
|
1430 // "+ count); |
|
1431 if (count < 0) |
|
1432 { |
|
1433 nBytes = (nBytes == 0) ? -1 : nBytes; |
|
1434 break; |
|
1435 } |
|
1436 nBytes += count; |
|
1437 } |
|
1438 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1439 "- NativeInputStream.read(,,,) return nBytes, " + nBytes); |
|
1440 return nBytes; |
|
1441 } |
|
1442 |
|
1443 private int readInner(byte[] aBytes, int aOffset, int aLength) |
|
1444 throws IOException |
|
1445 { |
|
1446 // Logger.LOG(Logger.ESOCKET, |
|
1447 // Logger.EInfo,"NativeInputStream.readInner() iOffset: "+ iOffset + |
|
1448 // "iLength: " + iLength); |
|
1449 if (iOffset == iLength) |
|
1450 { |
|
1451 getBytes(); |
|
1452 } |
|
1453 if (iLength == 0) |
|
1454 { |
|
1455 return EOF; |
|
1456 } |
|
1457 |
|
1458 int nBytesLeft = iLength - iOffset; |
|
1459 // Logger.LOG(Logger.ESOCKET, |
|
1460 // Logger.EInfo,"NativeInputStream.readInner() : nBytesLeft "+ |
|
1461 // nBytesLeft); |
|
1462 int nBytesToCopy = aLength > nBytesLeft ? nBytesLeft : aLength; |
|
1463 System.arraycopy(iBuffer, iOffset, aBytes, aOffset, nBytesToCopy); |
|
1464 iOffset += nBytesToCopy; |
|
1465 return nBytesToCopy; |
|
1466 } |
|
1467 |
|
1468 private void getBytes() throws IOException |
|
1469 { |
|
1470 int nBytes = iByteSource.getBytes(iBuffer, iBuffer.length); |
|
1471 |
|
1472 if (nBytes == -1) |
|
1473 { |
|
1474 throw new IOException(); |
|
1475 } |
|
1476 iLength = nBytes; |
|
1477 iOffset = 0; |
|
1478 } |
|
1479 |
|
1480 |
|
1481 /** |
|
1482 * Returns the number of bytes that can be read (or skipped over) from |
|
1483 * this input stream without blocking by the next caller of a method for |
|
1484 * this input stream. The next caller might be the same thread or |
|
1485 * another thread. |
|
1486 * |
|
1487 * @return the number of bytes that can be read from this input stream |
|
1488 * without blocking. |
|
1489 * @exception IOException |
|
1490 * if an I/O error occurs. |
|
1491 */ |
|
1492 public int available() throws IOException |
|
1493 { |
|
1494 throwIfClosed(); |
|
1495 return iByteSource.available(); |
|
1496 } |
|
1497 |
|
1498 private void throwIfClosed() throws IOException |
|
1499 { |
|
1500 if (iIsClosed) |
|
1501 { |
|
1502 throw new IOException("Connection is already closed"); |
|
1503 } |
|
1504 } |
|
1505 } |
|
1506 } |