forked from kangjianwei/LearningJDK
-
Notifications
You must be signed in to change notification settings - Fork 0
/
URLConnection.java
2047 lines (1810 loc) · 77.6 KB
/
URLConnection.java
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
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 1995, 2017, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package java.net;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.AccessController;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.StringTokenizer;
import java.util.concurrent.ConcurrentHashMap;
import sun.net.www.MessageHeader;
import sun.security.action.GetPropertyAction;
import sun.security.util.SecurityConstants;
/**
* The abstract class {@code URLConnection} is the superclass
* of all classes that represent a communications link between the
* application and a URL. Instances of this class can be used both to
* read from and to write to the resource referenced by the URL.
*
* <p>
* In general, creating a connection to a URL is a multistep process:
* <ol>
* <li>The connection object is created by invoking the
* {@link URL#openConnection() openConnection} method on a URL.
* <li>The setup parameters and general request properties are manipulated.
* <li>The actual connection to the remote object is made, using the
* {@link #connect() connect} method.
* <li>The remote object becomes available. The header fields and the contents
* of the remote object can be accessed.
* </ol>
* <p>
* The setup parameters are modified using the following methods:
* <ul>
* <li>{@code setAllowUserInteraction}
* <li>{@code setDoInput}
* <li>{@code setDoOutput}
* <li>{@code setIfModifiedSince}
* <li>{@code setUseCaches}
* </ul>
* <p>
* and the general request properties are modified using the method:
* <ul>
* <li>{@code setRequestProperty}
* </ul>
* <p>
* Default values for the {@code AllowUserInteraction} and
* {@code UseCaches} parameters can be set using the methods
* {@code setDefaultAllowUserInteraction} and
* {@code setDefaultUseCaches}.
* <p>
* Each of the above {@code set} methods has a corresponding
* {@code get} method to retrieve the value of the parameter or
* general request property. The specific parameters and general
* request properties that are applicable are protocol specific.
* <p>
* The following methods are used to access the header fields and
* the contents after the connection is made to the remote object:
* <ul>
* <li>{@code getContent}
* <li>{@code getHeaderField}
* <li>{@code getInputStream}
* <li>{@code getOutputStream}
* </ul>
* <p>
* Certain header fields are accessed frequently. The methods:
* <ul>
* <li>{@code getContentEncoding}
* <li>{@code getContentLength}
* <li>{@code getContentType}
* <li>{@code getDate}
* <li>{@code getExpiration}
* <li>{@code getLastModified}
* </ul>
* <p>
* provide convenient access to these fields. The
* {@code getContentType} method is used by the
* {@code getContent} method to determine the type of the remote
* object; subclasses may find it convenient to override the
* {@code getContentType} method.
* <p>
* In the common case, all of the pre-connection parameters and
* general request properties can be ignored: the pre-connection
* parameters and request properties default to sensible values. For
* most clients of this interface, there are only two interesting
* methods: {@code getInputStream} and {@code getContent},
* which are mirrored in the {@code URL} class by convenience methods.
* <p>
* More information on the request properties and header fields of
* an {@code http} connection can be found at:
* <blockquote><pre>
* <a href="http://www.ietf.org/rfc/rfc2616.txt">http://www.ietf.org/rfc/rfc2616.txt</a>
* </pre></blockquote>
*
* Invoking the {@code close()} methods on the {@code InputStream} or {@code OutputStream} of an
* {@code URLConnection} after a request may free network resources associated with this
* instance, unless particular protocol specifications specify different behaviours
* for it.
*
* @author James Gosling
* @see java.net.URL#openConnection()
* @see java.net.URLConnection#connect()
* @see java.net.URLConnection#getContent()
* @see java.net.URLConnection#getContentEncoding()
* @see java.net.URLConnection#getContentLength()
* @see java.net.URLConnection#getContentType()
* @see java.net.URLConnection#getDate()
* @see java.net.URLConnection#getExpiration()
* @see java.net.URLConnection#getHeaderField(int)
* @see java.net.URLConnection#getHeaderField(java.lang.String)
* @see java.net.URLConnection#getInputStream()
* @see java.net.URLConnection#getLastModified()
* @see java.net.URLConnection#getOutputStream()
* @see java.net.URLConnection#setAllowUserInteraction(boolean)
* @see java.net.URLConnection#setDefaultUseCaches(boolean)
* @see java.net.URLConnection#setDoInput(boolean)
* @see java.net.URLConnection#setDoOutput(boolean)
* @see java.net.URLConnection#setIfModifiedSince(long)
* @see java.net.URLConnection#setRequestProperty(java.lang.String, java.lang.String)
* @see java.net.URLConnection#setUseCaches(boolean)
* @since 1.0
*/
// URL资源连接的公共父类
public abstract class URLConnection {
private static final String contentClassPrefix = "sun.net.www.content";
private static final String contentPathProp = "java.content.handler.pkgs";
private static final ConcurrentHashMap<String, Boolean> defaultCaching = new ConcurrentHashMap<>();
/**
* @since 1.1
*/
// (全局)文件名到MIME类型的映射
private static volatile FileNameMap fileNameMap;
/**
* The ContentHandler factory.
*/
// (全局)资源内容句柄工厂
private static volatile ContentHandlerFactory factory;
// (全局)缓存"content-type"(MIME类型)到资源内容句柄的映射
private static final Hashtable<String, ContentHandler> handlers = new Hashtable<>();
private static boolean defaultAllowUserInteraction = false;
private static volatile boolean defaultUseCaches = true;
/**
* The URL represents the remote object on the World Wide Web to
* which this connection is opened.
* <p>
* The value of this field can be accessed by the
* {@code getURL} method.
* <p>
* The default value of this variable is the value of the URL
* argument in the {@code URLConnection} constructor.
*
* @see java.net.URLConnection#getURL()
* @see java.net.URLConnection#url
*/
// 指向资源的URL
protected URL url;
/**
* @since 1.6
*/
// 当前协议下的发起连接的请求信息
private MessageHeader requests;
/**
* If {@code false}, this connection object has not created a
* communications link to the specified URL. If {@code true},
* the communications link has been established.
*/
// 是否已建立连接
protected boolean connected = false;
/**
* This variable is set by the {@code setDoInput} method. Its
* value is returned by the {@code getDoInput} method.
* <p>
* A URL connection can be used for input and/or output. Setting the
* {@code doInput} flag to {@code true} indicates that
* the application intends to read data from the URL connection.
* <p>
* The default value of this field is {@code true}.
*
* @see java.net.URLConnection#getDoInput()
* @see java.net.URLConnection#setDoInput(boolean)
*/
// 是否允许从当前URL资源连接读取数据,默认为true;在某些协议的URL下,需要使用该参数做限制
protected boolean doInput = true;
/**
* This variable is set by the {@code setDoOutput} method. Its
* value is returned by the {@code getDoOutput} method.
* <p>
* A URL connection can be used for input and/or output. Setting the
* {@code doOutput} flag to {@code true} indicates
* that the application intends to write data to the URL connection.
* <p>
* The default value of this field is {@code false}.
*
* @see java.net.URLConnection#getDoOutput()
* @see java.net.URLConnection#setDoOutput(boolean)
*/
// 是否允许向当前URL资源连接写入数据,默认为false;在某些协议的URL下,需要使用该参数做限制
protected boolean doOutput = false;
/**
* If {@code true}, this {@code URL} is being examined in
* a context in which it makes sense to allow user interactions such
* as popping up an authentication dialog. If {@code false},
* then no user interaction is allowed.
* <p>
* The value of this field can be set by the
* {@code setAllowUserInteraction} method.
* Its value is returned by the
* {@code getAllowUserInteraction} method.
* Its default value is the value of the argument in the last invocation
* of the {@code setDefaultAllowUserInteraction} method.
*
* @see java.net.URLConnection#getAllowUserInteraction()
* @see java.net.URLConnection#setAllowUserInteraction(boolean)
* @see java.net.URLConnection#setDefaultAllowUserInteraction(boolean)
*/
protected boolean allowUserInteraction = defaultAllowUserInteraction;
/**
* If {@code true}, the protocol is allowed to use caching
* whenever it can. If {@code false}, the protocol must always
* try to get a fresh copy of the object.
* <p>
* This field is set by the {@code setUseCaches} method. Its
* value is returned by the {@code getUseCaches} method.
* <p>
* Its default value is the value given in the last invocation of the
* {@code setDefaultUseCaches} method.
* <p>
* The default setting may be overridden per protocol with
* {@link #setDefaultUseCaches(String, boolean)}.
*
* @see java.net.URLConnection#setUseCaches(boolean)
* @see java.net.URLConnection#getUseCaches()
* @see java.net.URLConnection#setDefaultUseCaches(boolean)
*/
protected boolean useCaches;
/**
* Some protocols support skipping the fetching of the object unless
* the object has been modified more recently than a certain time.
* <p>
* A nonzero value gives a time as the number of milliseconds since
* January 1, 1970, GMT. The object is fetched only if it has been
* modified more recently than that time.
* <p>
* This variable is set by the {@code setIfModifiedSince}
* method. Its value is returned by the
* {@code getIfModifiedSince} method.
* <p>
* The default value of this field is {@code 0}, indicating
* that the fetching must always occur.
*
* @see java.net.URLConnection#getIfModifiedSince()
* @see java.net.URLConnection#setIfModifiedSince(long)
*/
protected long ifModifiedSince = 0;
/**
* @since 1.5
*/
private int connectTimeout;
private int readTimeout;
/*▼ 构造器 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Constructs a URL connection to the specified URL. A connection to
* the object referenced by the URL is not created.
*
* @param url the specified URL.
*/
protected URLConnection(URL url) {
this.url = url;
if(url == null) {
this.useCaches = defaultUseCaches;
} else {
this.useCaches = getDefaultUseCaches(url.getProtocol());
}
}
/*▲ 构造器 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 连接 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Opens a communications link to the resource referenced by this
* URL, if such a connection has not already been established.
* <p>
* If the {@code connect} method is called when the connection
* has already been opened (indicated by the {@code connected}
* field having the value {@code true}), the call is ignored.
* <p>
* URLConnection objects go through two phases: first they are
* created, then they are connected. After being created, and
* before being connected, various options can be specified
* (e.g., doInput and UseCaches). After connecting, it is an
* error to try to set them. Operations that depend on being
* connected, like getContentLength, will implicitly perform the
* connection, if necessary.
*
* @throws SocketTimeoutException if the timeout expires before
* the connection can be established
* @throws IOException if an I/O error occurs while opening the
* connection.
* @see java.net.URLConnection#connected
* @see #getConnectTimeout()
* @see #setConnectTimeout(int)
*/
// 连接到当前URL指向的资源
public abstract void connect() throws IOException;
/*▲ 连接 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 字节流 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Returns an input stream that reads from this open connection.
*
* A SocketTimeoutException can be thrown when reading from the
* returned input stream if the read timeout expires before data
* is available for read.
*
* @return an input stream that reads from this open connection.
*
* @throws IOException if an I/O error occurs while creating the input stream.
* @throws UnknownServiceException if the protocol does not support input.
* @see #setReadTimeout(int)
* @see #getReadTimeout()
*/
// 返回指向当前URL资源的输入流,可以从中读取数据
public InputStream getInputStream() throws IOException {
throw new UnknownServiceException("protocol doesn't support input");
}
/**
* Returns an output stream that writes to this connection.
*
* @return an output stream that writes to this connection.
*
* @throws IOException if an I/O error occurs while creating the output stream.
* @throws UnknownServiceException if the protocol does not support output.
*/
// 返回指向当前URL资源的输出流,可以向其写入数据
public OutputStream getOutputStream() throws IOException {
throw new UnknownServiceException("protocol doesn't support output");
}
/*▲ 字节流 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 资源内容 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Retrieves the contents of this URL connection.
* <p>
* This method first determines the content type of the object by
* calling the {@code getContentType} method. If this is
* the first time that the application has seen that specific content
* type, a content handler for that content type is created.
* <p> This is done as follows:
* <ol>
* <li>If the application has set up a content handler factory instance
* using the {@code setContentHandlerFactory} method, the
* {@code createContentHandler} method of that instance is called
* with the content type as an argument; the result is a content
* handler for that content type.
* <li>If no {@code ContentHandlerFactory} has yet been set up,
* or if the factory's {@code createContentHandler} method
* returns {@code null}, then the {@linkplain java.util.ServiceLoader
* ServiceLoader} mechanism is used to locate {@linkplain
* java.net.ContentHandlerFactory ContentHandlerFactory}
* implementations using the system class
* loader. The order that factories are located is implementation
* specific, and an implementation is free to cache the located
* factories. A {@linkplain java.util.ServiceConfigurationError
* ServiceConfigurationError}, {@code Error} or {@code RuntimeException}
* thrown from the {@code createContentHandler}, if encountered, will
* be propagated to the calling thread. The {@code
* createContentHandler} method of each factory, if instantiated, is
* invoked, with the content type, until a factory returns non-null,
* or all factories have been exhausted.
* <li>Failing that, this method tries to load a content handler
* class as defined by {@link java.net.ContentHandler ContentHandler}.
* If the class does not exist, or is not a subclass of {@code
* ContentHandler}, then an {@code UnknownServiceException} is thrown.
* </ol>
*
* @return the object fetched. The {@code instanceof} operator
* should be used to determine the specific kind of object
* returned.
*
* @throws IOException if an I/O error occurs while
* getting the content.
* @throws UnknownServiceException if the protocol does not support
* the content type.
* @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
* @see java.net.URLConnection#getContentType()
* @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
*/
// 返回目标资源的内容,返回的形式取决于资源的类型(不一定总是输入流)
public Object getContent() throws IOException {
/*
* Must call getInputStream before GetHeaderField gets called
* so that FileNotFoundException has a chance to be thrown up
* from here without being caught.
*/
getInputStream();
// 获取当前URL指向的内容对应的资源内容句柄
ContentHandler contentHandler = getContentHandler();
// 返回目标资源的内容,返回的形式取决于资源的类型
return contentHandler.getContent(this);
}
/**
* Retrieves the contents of this URL connection.
*
* @param classes the {@code Class} array
* indicating the requested types
*
* @return the object fetched that is the first match of the type
* specified in the classes array. null if none of
* the requested types are supported.
* The {@code instanceof} operator should be used to
* determine the specific kind of object returned.
*
* @throws IOException if an I/O error occurs while
* getting the content.
* @throws UnknownServiceException if the protocol does not support
* the content type.
* @see java.net.URLConnection#getContent()
* @see java.net.ContentHandlerFactory#createContentHandler(java.lang.String)
* @see java.net.URLConnection#getContent(java.lang.Class[])
* @see java.net.URLConnection#setContentHandlerFactory(java.net.ContentHandlerFactory)
* @since 1.3
*/
// 返回目标资源的内容,且限定该"内容"只能是指定的类型;内容的返回形式取决于资源的类型(不一定总是输入流)
public Object getContent(Class<?>[] classes) throws IOException {
/*
* Must call getInputStream before GetHeaderField gets called
* so that FileNotFoundException has a chance to be thrown up
* from here without being caught.
*/
getInputStream();
// 获取当前URL指向的内容对应的资源内容句柄
ContentHandler contentHandler = getContentHandler();
// 返回目标资源的内容,且限定该"内容"只能是指定的类型;内容的返回形式取决于资源的类型
return contentHandler.getContent(this, classes);
}
/*▲ 资源内容 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 请求头 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Sets the general request property.
* If a property with the key already exists, overwrite its value with the new value.
*
* <p> NOTE: HTTP requires all request properties which can
* legally have multiple instances with the same key
* to use a comma-separated list syntax which enables multiple
* properties to be appended into a single property.
*
* @param key the keyword by which the request is known (e.g., "{@code Accept}").
* @param value the value associated with it.
*
* @throws IllegalStateException if already connected
* @throws NullPointerException if key is {@code null}
* @see #getRequestProperty(java.lang.String)
*/
// 设置请求头,通常在http(s)协议中被使用
public void setRequestProperty(String key, String value) {
checkConnected();
if(key == null) {
throw new NullPointerException("key is null");
}
if(requests == null) {
requests = new MessageHeader();
}
requests.set(key, value);
}
/**
* Adds a general request property specified by a
* key-value pair. This method will not overwrite
* existing values associated with the same key.
*
* @param key the keyword by which the request is known
* (e.g., "{@code Accept}").
* @param value the value associated with it.
*
* @throws IllegalStateException if already connected
* @throws NullPointerException if key is null
* @see #getRequestProperties()
* @since 1.4
*/
// 添加请求头,通常在http(s)协议中被使用
public void addRequestProperty(String key, String value) {
checkConnected();
if(key == null) {
throw new NullPointerException("key is null");
}
if(requests == null) {
requests = new MessageHeader();
}
requests.add(key, value);
}
/**
* Returns an unmodifiable Map of general request
* properties for this connection. The Map keys
* are Strings that represent the request-header
* field names. Each Map value is a unmodifiable List
* of Strings that represents the corresponding
* field values.
*
* @return a Map of the general request properties for this connection.
*
* @throws IllegalStateException if already connected
* @since 1.4
*/
// 获取请求头,通常在http(s)协议中被使用
public Map<String, List<String>> getRequestProperties() {
checkConnected();
if(requests == null) {
return Collections.emptyMap();
}
return requests.getHeaders(null);
}
/**
* Returns the value of the named general request property for this
* connection.
*
* @param key the keyword by which the request is known (e.g., "Accept").
*
* @return the value of the named general request property for this
* connection. If key is null, then null is returned.
*
* @throws IllegalStateException if already connected
* @see #setRequestProperty(java.lang.String, java.lang.String)
*/
// 获取指定key的请求头,通常在http(s)协议中被使用
public String getRequestProperty(String key) {
checkConnected();
if(requests == null) {
return null;
}
return requests.findValue(key);
}
/*▲ 请求头 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 头信息 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Returns the value of the named header field.
* <p>
* If called on a connection that sets the same header multiple times
* with possibly different values, only the last value is returned.
*
* @param name the name of a header field.
*
* @return the value of the named header field, or {@code null}
* if there is no such field in the header.
*/
// 返回指定名称的头信息的值,由子类覆盖实现
public String getHeaderField(String name) {
return null;
}
/**
* Returns the key for the {@code n}<sup>th</sup> header field.
* It returns {@code null} if there are fewer than {@code n+1} fields.
*
* @param n an index, where {@code n>=0}
*
* @return the key for the {@code n}<sup>th</sup> header field,
* or {@code null} if there are fewer than {@code n+1}
* fields.
*/
// 返回第n(>=0)条头信息的key,由子类覆盖实现
public String getHeaderFieldKey(int n) {
return null;
}
/**
* Returns the value for the {@code n}<sup>th</sup> header field.
* It returns {@code null} if there are fewer than
* {@code n+1}fields.
* <p>
* This method can be used in conjunction with the
* {@link #getHeaderFieldKey(int) getHeaderFieldKey} method to iterate through all
* the headers in the message.
*
* @param n an index, where {@code n>=0}
*
* @return the value of the {@code n}<sup>th</sup> header field
* or {@code null} if there are fewer than {@code n+1} fields
*
* @see java.net.URLConnection#getHeaderFieldKey(int)
*/
// 返回第n(>=0)条头信息的value,由子类覆盖实现
public String getHeaderField(int n) {
return null;
}
/**
* Returns an unmodifiable Map of the header fields.
* The Map keys are Strings that represent the
* response-header field names. Each Map value is an
* unmodifiable List of Strings that represents
* the corresponding field values.
*
* @return a Map of header fields
*
* @since 1.4
*/
// 返回头信息,由子类覆盖实现
public Map<String, List<String>> getHeaderFields() {
return Collections.emptyMap();
}
/**
* Returns the value of the named field parsed as a number.
* <p>
* This form of {@code getHeaderField} exists because some
* connection types (e.g., {@code http-ng}) have pre-parsed
* headers. Classes for that connection type can override this method
* and short-circuit the parsing.
*
* @param name the name of the header field.
* @param Default the default value.
*
* @return the value of the named field, parsed as an integer. The
* {@code Default} value is returned if the field is
* missing or malformed.
*/
// 返回指定名称的int类型的头信息;如果不存在,则解析默认值Default
public int getHeaderFieldInt(String name, int Default) {
String value = getHeaderField(name);
try {
return Integer.parseInt(value);
} catch(Exception e) {
}
return Default;
}
/**
* Returns the value of the named field parsed as a number.
* <p>
* This form of {@code getHeaderField} exists because some
* connection types (e.g., {@code http-ng}) have pre-parsed
* headers. Classes for that connection type can override this method
* and short-circuit the parsing.
*
* @param name the name of the header field.
* @param Default the default value.
*
* @return the value of the named field, parsed as a long. The
* {@code Default} value is returned if the field is
* missing or malformed.
*
* @since 1.7
*/
// 返回指定名称的long类型的头信息;如果不存在,则解析默认值Default
public long getHeaderFieldLong(String name, long Default) {
String value = getHeaderField(name);
try {
return Long.parseLong(value);
} catch(Exception e) {
}
return Default;
}
/**
* Returns the value of the named field parsed as date.
* The result is the number of milliseconds since January 1, 1970 GMT
* represented by the named field.
* <p>
* This form of {@code getHeaderField} exists because some
* connection types (e.g., {@code http-ng}) have pre-parsed
* headers. Classes for that connection type can override this method
* and short-circuit the parsing.
*
* @param name the name of the header field.
* @param Default a default value.
*
* @return the value of the field, parsed as a date. The value of the
* {@code Default} argument is returned if the field is
* missing or malformed.
*/
// 返回指定名称的日期类型的头信息;如果不存在,则将默认值Default解析为日期返回
@SuppressWarnings("deprecation")
public long getHeaderFieldDate(String name, long Default) {
String value = getHeaderField(name);
try {
return Date.parse(value);
} catch(Exception e) {
}
return Default;
}
/*▲ 头信息 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ 消息头 ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Returns the value of the {@code content-length} header field.
* <P>
* <B>Note</B>: {@link #getContentLengthLong() getContentLengthLong()}
* should be preferred over this method, since it returns a {@code long}
* instead and is therefore more portable.</P>
*
* @return the content length of the resource that this connection's URL
* references, {@code -1} if the content length is not known,
* or if the content length is greater than Integer.MAX_VALUE.
*/
// 返回"content-length"
public int getContentLength() {
long l = getContentLengthLong();
if(l>Integer.MAX_VALUE) {
return -1;
}
return (int) l;
}
/**
* Returns the value of the {@code content-length} header field as a
* long.
*
* @return the content length of the resource that this connection's URL
* references, or {@code -1} if the content length is
* not known.
*
* @since 1.7
*/
// 返回"content-length",以long形式返回
public long getContentLengthLong() {
return getHeaderFieldLong("content-length", -1);
}
/**
* Returns the value of the {@code content-type} header field.
*
* @return the content type of the resource that the URL references,
* or {@code null} if not known.
*
* @see java.net.URLConnection#getHeaderField(java.lang.String)
*/
// 返回MIME信息头中的"content-type"(MIME类型)
public String getContentType() {
return getHeaderField("content-type");
}
/**
* Returns the value of the {@code content-encoding} header field.
*
* @return the content encoding of the resource that the URL references,
* or {@code null} if not known.
*
* @see java.net.URLConnection#getHeaderField(java.lang.String)
*/
// 返回"content-encoding"
public String getContentEncoding() {
return getHeaderField("content-encoding");
}
/**
* Returns the value of the {@code expires} header field.
*
* @return the expiration date of the resource that this URL references,
* or 0 if not known. The value is the number of milliseconds since
* January 1, 1970 GMT.
*
* @see java.net.URLConnection#getHeaderField(java.lang.String)
*/
// 返回"expires"
public long getExpiration() {
return getHeaderFieldDate("expires", 0);
}
/**
* Returns the value of the {@code date} header field.
*
* @return the sending date of the resource that the URL references,
* or {@code 0} if not known. The value returned is the
* number of milliseconds since January 1, 1970 GMT.
*
* @see java.net.URLConnection#getHeaderField(java.lang.String)
*/
// 返回"date"
public long getDate() {
return getHeaderFieldDate("date", 0);
}
/**
* Returns the value of the {@code last-modified} header field.
* The result is the number of milliseconds since January 1, 1970 GMT.
*
* @return the date the resource referenced by this
* {@code URLConnection} was last modified, or 0 if not known.
*
* @see java.net.URLConnection#getHeaderField(java.lang.String)
*/
// 返回"last-modified"
public long getLastModified() {
return getHeaderFieldDate("last-modified", 0);
}
/*▲ 消息头 ████████████████████████████████████████████████████████████████████████████████┛ */
/*▼ get ████████████████████████████████████████████████████████████████████████████████┓ */
/**
* Returns the value of this {@code URLConnection}'s {@code URL}
* field.
*
* @return the value of this {@code URLConnection}'s {@code URL}
* field.
*
* @see java.net.URLConnection#url
*/
// 返回当前(资源)连接的URL
public URL getURL() {
return url;
}
/**
* Loads filename map (a mimetable) from a data file.
* It will first try to load the user-specific table, defined by content.types.user.table property.
* If that fails, it tries to load the default built-in table.
*
* @return the FileNameMap
*
* @see #setFileNameMap(java.net.FileNameMap)
* @since 1.2
*/
// 返回文件名到MIME类型的映射
public static FileNameMap getFileNameMap() {
if(fileNameMap != null) {
return fileNameMap;
}
fileNameMap = new FileNameMap() {
// 获取一个MIME信息表
private FileNameMap internalMap = sun.net.www.MimeTable.loadTable();
// 返回指定文件名对应的MIME类型
public String getContentTypeFor(String fileName) {
return internalMap.getContentTypeFor(fileName);
}
};
return fileNameMap;
}
/**
* Tries to determine the content type of an object, based
* on the specified "file" component of a URL.
* This is a convenience method that can be used by
* subclasses that override the {@code getContentType} method.
*
* @param fname a filename.
*
* @return a guess as to what the content type of the object is,
* based upon its file name.
*
* @see java.net.URLConnection#getContentType()
*/
// 返回(猜测)指定文件名对应的MIME类型
public static String guessContentTypeFromName(String fname) {
// 获取文件名到MIME类型的映射
FileNameMap fileNameMap = getFileNameMap();
// 返回指定文件名对应的MIME类型
return fileNameMap.getContentTypeFor(fname);
}
/**
* Tries to determine the type of an input stream based on the characters at the beginning of the input stream.
* This method can be used by subclasses that override the {@code getContentType} method.
* <p>
* Ideally, this routine would not be needed. But many
* {@code http} servers return the incorrect content type; in
* addition, there are many nonstandard extensions. Direct inspection
* of the bytes to determine the content type is often more accurate
* than believing the content type claimed by the {@code http} server.
*
* @param is an input stream that supports marks.
*
* @return a guess at the content type, or {@code null} if none
* can be determined.
*
* @throws IOException if an I/O error occurs while reading the input stream.
* @see java.io.InputStream#mark(int)
* @see java.io.InputStream#markSupported()
* @see java.net.URLConnection#getContentType()
*/
// 对于特定类型的文件,可以通过解析其输入流的前几个字节来猜测该文件的真实类型
public static String guessContentTypeFromStream(InputStream is) throws IOException {
// If we can't read ahead safely, just give up on guessing
if(!is.markSupported()) {
return null;
}
is.mark(16);
int c1 = is.read();
int c2 = is.read();
int c3 = is.read();
int c4 = is.read();
int c5 = is.read();
int c6 = is.read();
int c7 = is.read();
int c8 = is.read();
int c9 = is.read();