76 protected final static int SETUP = 1; |
76 protected final static int SETUP = 1; |
77 protected final static int CONNECTED = 2; |
77 protected final static int CONNECTED = 2; |
78 protected final static int REQUEST_HEADERS_SENT = 3; |
78 protected final static int REQUEST_HEADERS_SENT = 3; |
79 protected final static int REQUEST_SENT = 4; |
79 protected final static int REQUEST_SENT = 4; |
80 protected final static int REPLY_RECEIVED = 5; |
80 protected final static int REPLY_RECEIVED = 5; |
|
81 protected final static int PARTIAL_REQUEST_SENT = 6; |
81 |
82 |
82 // Character constants |
83 // Character constants |
83 protected final static char HASH = '#'; |
84 protected final static char HASH = '#'; |
84 protected final static int QUESTION_MARK = 63; |
85 protected final static int QUESTION_MARK = 63; |
85 protected final static int CR = 13; |
86 protected final static int CR = 13; |
129 protected AccessPoint iApn = null; |
130 protected AccessPoint iApn = null; |
130 private static boolean iIsSessionDeleted = false; |
131 private static boolean iIsSessionDeleted = false; |
131 private boolean iTrustedSuite = true; |
132 private boolean iTrustedSuite = true; |
132 private int iRespTimeOut = -1; |
133 private int iRespTimeOut = -1; |
133 private int iRetries = 0; |
134 private int iRetries = 0; |
|
135 private int iRequestBodyLen = -1; |
|
136 private int iTotalPostDataLen = 0; |
|
137 private boolean iEndOfRequest = false; |
|
138 private boolean iChunkedTransfer = false; |
|
139 |
|
140 protected final BlockingOperation iPostDataBlock; |
134 |
141 |
135 static |
142 static |
136 { |
143 { |
137 try |
144 try |
138 { |
145 { |
192 |
199 |
193 // Blocking operations to allow async native transactions |
200 // Blocking operations to allow async native transactions |
194 iTransactionBlock = new BlockingOperation(); |
201 iTransactionBlock = new BlockingOperation(); |
195 iNativeDataReadyForRead = new BlockingOperation(); |
202 iNativeDataReadyForRead = new BlockingOperation(); |
196 iNativeDataReadyForRead.setResult(BlockingOperation.BLOCKED); |
203 iNativeDataReadyForRead.setResult(BlockingOperation.BLOCKED); |
|
204 iPostDataBlock = new BlockingOperation(); |
197 iFinalizer = registerForFinalization(); |
205 iFinalizer = registerForFinalization(); |
198 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- HttpConnectionNative new "); |
206 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- HttpConnectionNative new "); |
199 |
207 |
200 ApplicationInfo appInfo = ApplicationInfo.getInstance(); |
208 ApplicationInfo appInfo = ApplicationInfo.getInstance(); |
201 String runtime = appInfo.getRuntimeType(); |
209 String runtime = appInfo.getRuntimeType(); |
811 iRequestProperties.put(aKey, val); |
819 iRequestProperties.put(aKey, val); |
812 } |
820 } |
813 else |
821 else |
814 { |
822 { |
815 iRequestProperties.put(aKey, aValue); |
823 iRequestProperties.put(aKey, aValue); |
|
824 } |
|
825 if (aKey.equals(TRANSFER_ENCODING)) |
|
826 { |
|
827 String tmp = aValue.toLowerCase(); |
|
828 if (tmp.equals("chunked")) |
|
829 { |
|
830 iChunkedTransfer = true; |
|
831 iRequestBodyLen = -1; // as per RFC, precedence should be give to "transfer-encoding" when "content-length" is also set. |
|
832 } |
|
833 } |
|
834 if (aKey.equals(CONTENT_LENGTH)) |
|
835 { |
|
836 iRequestBodyLen = Integer.parseInt(aValue); |
|
837 |
816 } |
838 } |
817 } |
839 } |
818 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- setRequestProperty(String, String)" ); |
840 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- setRequestProperty(String, String)" ); |
819 return; |
841 return; |
820 } |
842 } |
862 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
884 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
863 "-------- inputStreamClosed()"); |
885 "-------- inputStreamClosed()"); |
864 } |
886 } |
865 |
887 |
866 |
888 |
867 protected synchronized void outputStreamFlushed() throws IOException |
889 private void waitForPostDataCompletion() |
868 { |
890 { |
869 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ outputStreamFlushed()" ); |
891 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+waitForPostDataCompletion"); |
|
892 iPostDataBlock.waitForCompletion(); |
|
893 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "-waitForPostDataCompletion"); |
|
894 |
|
895 } |
|
896 |
|
897 private synchronized void sendPartialRequest() throws IOException |
|
898 { |
|
899 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "HTTP sendPartialRequest() "); |
870 switch (iState) |
900 switch (iState) |
871 { |
901 { |
872 case SETUP: |
902 case SETUP: |
873 case CONNECTED: |
903 case CONNECTED: |
874 case REQUEST_HEADERS_SENT: |
904 |
875 ensureResponse(); |
905 synchronized (iPostDataBlock.getLock()) |
|
906 { |
|
907 synchronized (iPostDataBlock) |
|
908 { |
|
909 sendRequest(true); |
|
910 iPostedDataStream.reset(); |
|
911 waitForPostDataCompletion(); |
|
912 } |
|
913 } |
876 break; |
914 break; |
877 |
915 |
878 default: |
916 case PARTIAL_REQUEST_SENT : |
879 // No-op |
917 |
880 ; |
918 byte[] postData = iPostedDataStream.toByteArray(); |
|
919 iPostedDataStream.reset(); |
|
920 int len = -1; |
|
921 if (postData != null) |
|
922 { |
|
923 len = postData.length; |
|
924 iTotalPostDataLen = iTotalPostDataLen + len; |
|
925 } |
|
926 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "HTTP content-len = "+iRequestBodyLen + " totalflushed = "+ iTotalPostDataLen +" os len = "+ postData.length); |
|
927 if (iTotalPostDataLen == iRequestBodyLen) |
|
928 { |
|
929 iEndOfRequest = true; |
|
930 } |
|
931 |
|
932 synchronized (iPostDataBlock.getLock()) |
|
933 { |
|
934 synchronized (iPostDataBlock) |
|
935 { |
|
936 int err = _postData(iNativeTransactionHande, postData, len, iEndOfRequest); |
|
937 |
|
938 if (err != 0) |
|
939 { |
|
940 throwIOException("Unable to write data .Symbian os error code: " |
|
941 + err); |
|
942 } |
|
943 if (iEndOfRequest == false) |
|
944 { |
|
945 // wait until http stack consumes the data |
|
946 waitForPostDataCompletion(); |
|
947 } |
|
948 else |
|
949 { |
|
950 // request complete, wait until the first chunk of response header arrives |
|
951 synchronized (iTransactionBlock.getLock()) |
|
952 { |
|
953 synchronized (iTransactionBlock) |
|
954 { |
|
955 waitForTransaction(); |
|
956 } |
|
957 } |
|
958 |
|
959 } // end else |
|
960 } // end syn |
|
961 |
|
962 } // end syn getlock |
|
963 |
|
964 break; |
|
965 } |
|
966 |
|
967 } |
|
968 |
|
969 protected synchronized void outputStreamFlushed() throws IOException |
|
970 { |
|
971 int postDataLength = iPostedDataStream.size(); |
|
972 |
|
973 |
|
974 if ((iRequestBodyLen > postDataLength) || (iChunkedTransfer == true)) |
|
975 { |
|
976 // chunked http request will be sent in two cases |
|
977 // 1) application sets "Content-Lenght" request header and writes to output stream multiple times using flush |
|
978 // like a sequence of os.write(); os.flush() operations |
|
979 // 2) application sets "Transfer-Encoding" request header and writes to ouput stream multiple times using flush |
|
980 sendPartialRequest(); |
|
981 |
|
982 } |
|
983 else |
|
984 { |
|
985 switch (iState) |
|
986 { |
|
987 case SETUP: |
|
988 case CONNECTED: |
|
989 case REQUEST_HEADERS_SENT: |
|
990 ensureResponse(); |
|
991 break; |
|
992 |
|
993 default: |
|
994 // No-op |
|
995 ; |
|
996 } |
881 } |
997 } |
882 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- outputStreamFlushed()" ); |
998 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- outputStreamFlushed()" ); |
883 } |
999 } |
884 |
1000 |
885 protected synchronized void outputStreamClosed() throws IOException |
1001 protected synchronized void outputStreamClosed() throws IOException |
936 } |
1052 } |
937 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureOpen()" ); |
1053 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- ensureOpen()" ); |
938 return; |
1054 return; |
939 } |
1055 } |
940 |
1056 |
|
1057 private void waitForResponse() throws IOException |
|
1058 { |
|
1059 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "HTTP flush case, waitForResponse: total len = "+iRequestBodyLen + " totalflushed = "+ iTotalPostDataLen ); |
|
1060 if (iEndOfRequest == false) |
|
1061 { |
|
1062 // chunked http request was sent, but end of request not sent |
|
1063 // only in case of "transfer-encoding" request header, control will come here |
|
1064 iEndOfRequest = true; |
|
1065 byte[] postData = iPostedDataStream.toByteArray(); |
|
1066 iPostedDataStream.reset(); |
|
1067 int len = -1; |
|
1068 if (postData != null) |
|
1069 { |
|
1070 len = postData.length; |
|
1071 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "More data left in os, len = "+len); |
|
1072 iTotalPostDataLen = iTotalPostDataLen + len; |
|
1073 } |
|
1074 int err = _postData(iNativeTransactionHande, postData, len , iEndOfRequest); |
|
1075 if (err != 0) |
|
1076 { |
|
1077 throwIOException("Unable to write data .Symbian os error code: " |
|
1078 + err); |
|
1079 } |
|
1080 synchronized (iTransactionBlock.getLock()) |
|
1081 { |
|
1082 synchronized (iTransactionBlock) |
|
1083 { |
|
1084 waitForTransaction(); |
|
1085 } |
|
1086 } |
|
1087 } |
|
1088 getResponse(); |
|
1089 iState = REPLY_RECEIVED; |
|
1090 |
|
1091 } |
|
1092 |
941 protected void ensureResponse() throws IOException |
1093 protected void ensureResponse() throws IOException |
942 { |
1094 { |
943 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureResponse()" ); |
1095 // Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ ensureResponse()" ); |
944 ensureConnected(); |
1096 ensureConnected(); |
945 switch (iState) |
1097 switch (iState) |
946 { |
1098 { |
|
1099 case PARTIAL_REQUEST_SENT: |
|
1100 waitForResponse(); |
|
1101 break; |
|
1102 |
947 case CONNECTED: |
1103 case CONNECTED: |
948 |
1104 |
949 sendRequest(); |
1105 sendRequest(false); // sendRequest() will block until the first chunk of http response arrives from the server. |
950 // Fall Through |
1106 // Fall Through |
951 case REQUEST_HEADERS_SENT: |
1107 case REQUEST_HEADERS_SENT: |
952 case REQUEST_SENT: |
1108 case REQUEST_SENT: |
953 getResponse(); |
1109 getResponse(); |
954 iState = REPLY_RECEIVED; |
1110 iState = REPLY_RECEIVED; |
1071 sepIndex = -1; |
1227 sepIndex = -1; |
1072 } |
1228 } |
1073 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- readHeaders(InputStream)" ); |
1229 //Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- readHeaders(InputStream)" ); |
1074 } |
1230 } |
1075 |
1231 |
1076 protected synchronized void sendRequest() throws IOException |
1232 protected synchronized void sendRequest(boolean aPartialDataFlag) throws IOException |
1077 { |
1233 { |
1078 ensureConnected(); |
1234 ensureConnected(); |
|
1235 Logger.PLOG(Logger.ESOCKET, "HTTP sendRequest() , Flag : " + aPartialDataFlag); |
1079 final int count = iRequestProperties.size(); |
1236 final int count = iRequestProperties.size(); |
1080 int headerCount = count; |
1237 int headerCount = count; |
1081 |
1238 |
1082 final Enumeration keyEnum = iRequestProperties.keys(); |
1239 final Enumeration keyEnum = iRequestProperties.keys(); |
1083 String[] headers = null; |
1240 String[] headers = null; |
1117 synchronized (iTransactionBlock) |
1275 synchronized (iTransactionBlock) |
1118 { |
1276 { |
1119 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1277 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1120 "before _submitTransaction "); |
1278 "before _submitTransaction "); |
1121 final int err = _submitTransaction(iNativeTransactionHande, |
1279 final int err = _submitTransaction(iNativeTransactionHande, |
1122 headers, postData, postDataLength,iRespTimeOut); |
1280 headers, postData, postDataLength,iRespTimeOut, aPartialDataFlag); |
1123 |
1281 |
1124 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1282 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1125 "-_submitTransaction +err " + err); |
1283 "-_submitTransaction +err " + err); |
1126 |
1284 |
1127 // Clear tempory byte array and headers array |
1285 // Clear tempory byte array and headers array |
1128 postData = null; |
1286 postData = null; |
1129 headers = null; |
1287 headers = null; |
1130 if (err != 0) |
1288 if (err != 0) |
1131 throwIOException("Unable to connect to server.Symbian os error code: " |
1289 throwIOException("Unable to connect to server.Symbian os error code: " |
1132 + err); |
1290 + err); |
1133 iState = REQUEST_SENT; |
1291 if (aPartialDataFlag == true) |
1134 waitForTransaction(); |
1292 { |
|
1293 iState = PARTIAL_REQUEST_SENT; |
|
1294 iTotalPostDataLen = iTotalPostDataLen + postDataLength; |
|
1295 } |
|
1296 else |
|
1297 { |
|
1298 // block and wait for response headers only when it a complete request |
|
1299 iState = REQUEST_SENT; |
|
1300 waitForTransaction(); |
|
1301 } |
1135 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1302 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1136 "- sendRequest _submitTransaction"); |
1303 "- sendRequest _submitTransaction"); |
1137 } |
1304 } |
1138 } |
1305 } |
1139 if ((iTransactionBlock.getResult() == -18) &&(iRetries < 2)) |
1306 if (aPartialDataFlag == false) |
1140 { |
1307 { |
1141 iRetries++; |
1308 if ((iTransactionBlock.getResult() == -18) &&(iRetries < 2)) |
1142 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1309 { |
1143 "- sendRequest KErrNotReady erroi, calling recursive sendRequest()"); |
1310 iRetries++; |
1144 sendRequest(); |
1311 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1145 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
1312 "- sendRequest KErrNotReady erroi, calling recursive sendRequest()"); |
1146 "- sendRequest KErrNotReady erroi, calling recursive sendRequest() returned"); |
1313 sendRequest(false); |
|
1314 Logger.LOG(Logger.ESOCKET, Logger.EInfo, |
|
1315 "- sendRequest KErrNotReady erroi, calling recursive sendRequest() returned"); |
|
1316 } |
1147 } |
1317 } |
1148 } |
1318 } |
1149 |
1319 |
1150 protected void throwIOException(String aMessage) throws IOException |
1320 protected void throwIOException(String aMessage) throws IOException |
1151 { |
1321 { |
1289 + aStatus); |
1459 + aStatus); |
1290 iNativeDataReadyForRead.notifyCompleted(aStatus); |
1460 iNativeDataReadyForRead.notifyCompleted(aStatus); |
1291 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- dataReadyForReadCallBack"); |
1461 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "- dataReadyForReadCallBack"); |
1292 } |
1462 } |
1293 |
1463 |
|
1464 protected void postDataConsumedCallback() |
|
1465 { |
|
1466 Logger.LOG(Logger.ESOCKET, Logger.EInfo, "+ postDataconsumedCallback "); |
|
1467 iPostDataBlock.notifyCompleted(0); |
|
1468 |
|
1469 } |
|
1470 |
1294 /* |
1471 /* |
1295 * Native Calls |
1472 * Native Calls |
1296 */ |
1473 */ |
1297 private native int _createHttpSession(int a, int aType, int aApn, |
1474 private native int _createHttpSession(int a, int aType, int aApn, |
1298 int[] retval); |
1475 int[] retval); |
1299 private native int _createNativeTransaction(int aNativeHttpSessionHandle, |
1476 private native int _createNativeTransaction(int aNativeHttpSessionHandle, |
1300 String aUri, String aRequestMethod); |
1477 String aUri, String aRequestMethod); |
1301 private native int _submitTransaction(int aNativeTransactionHande, |
1478 private native int _submitTransaction(int aNativeTransactionHande, |
1302 String[] aHeaders, byte[] aPostData, int aPostLength, |
1479 String[] aHeaders, byte[] aPostData, int aPostLength, |
1303 int aRespTimeOut); |
1480 int aRespTimeOut, boolean aPartialData); |
1304 private native String[] _getResponse(int aNativeTransactionHande); |
1481 private native String[] _getResponse(int aNativeTransactionHande); |
1305 private native int _getBytes(int aNativeTransactionHande, byte[] aBuffer, |
1482 private native int _getBytes(int aNativeTransactionHande, byte[] aBuffer, |
1306 int aLength); |
1483 int aLength); |
1307 private native void _closeTransaction(int aNativeTransactionHande); |
1484 private native void _closeTransaction(int aNativeTransactionHande); |
1308 private native int _available(int aNativeTransactionHande); |
1485 private native int _available(int aNativeTransactionHande); |
1309 private native String _getUserAgentHeaderValue(boolean aMidpRuntime); |
1486 private native String _getUserAgentHeaderValue(boolean aMidpRuntime); |
|
1487 private native int _postData(int aNativeTransactionHandle, byte[] aPostData, int aLength, boolean iEndOfRequest); |
1310 |
1488 |
1311 /* |
1489 /* |
1312 * |
1490 * |
1313 * class PlainDataInputStream |
1491 * class PlainDataInputStream |
1314 * |
1492 * |