2012-03-07 65 views
5

मुझे निम्न समस्या का सामना करना पड़ा: जब URLConnection प्रॉक्सी के माध्यम से उपयोग किया जाता है तो सामग्री की लंबाई हमेशा -1 पर सेट होती है।URLConnection प्रॉक्सी के माध्यम से सामग्री लंबाई को सही ढंग से संभाल नहीं करता

सबसे पहले मैं जाँच की है कि प्रॉक्सी वास्तव में Content-Length रिटर्न (lynx और wget भी प्रॉक्सी के माध्यम से काम कर रहे हैं, वहाँ स्थानीय नेटवर्क से इंटरनेट पर जाने के लिए कोई दूसरा रास्ता नहीं है):

$ lynx -source -head ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip 
HTTP/1.1 200 OK 
Last-Modified: Mon, 09 Jul 2007 17:02:37 GMT 
Content-Type: application/x-zip-compressed 
Content-Length: 30745 
Connection: close 
Date: Thu, 02 Feb 2012 17:18:52 GMT 

$ wget -S -X HEAD ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip 
--2012-04-03 19:36:54-- ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip 
Resolving proxy... 10.10.0.12 
Connecting to proxy|10.10.0.12|:8080... connected. 
Proxy request sent, awaiting response... 
    HTTP/1.1 200 OK 
    Last-Modified: Mon, 09 Jul 2007 17:02:37 GMT 
    Content-Type: application/x-zip-compressed 
    Content-Length: 30745 
    Connection: close 
    Age: 0 
    Date: Tue, 03 Apr 2012 17:36:54 GMT 
Length: 30745 (30K) [application/x-zip-compressed] 
Saving to: `WO2003-104476-001.zip' 

जावा में मैं ने लिखा है:

URL url = new URL("ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip"); 
int length = url.openConnection().getContentLength(); 
logger.debug("Got length: " + length); 

और मुझे -1 मिलता है। मैं FtpURLConnection डिबग करने के लिए शुरू किया और यह पता चला कि आवश्यक जानकारी HttpURLConnection.responses क्षेत्र लेकिन यह ठीक से वहाँ से आबादी वाले कभी नहीं है अंतर्निहित में है:

enter image description here (वहाँ हेडर में Content-Length: 30745)। जब आप स्ट्रीम पढ़ना शुरू करते हैं या स्ट्रीम पढ़ने के बाद भी सामग्री की लंबाई अपडेट नहीं होती है। कोड:

URL url = new URL("ftp://ftp.wipo.int/pub/published_pct_sequences/publication/2003/1218/WO03_104476/WO2003-104476-001.zip"); 
URLConnection connection = url.openConnection(); 

logger.debug("Got length (1): " + connection.getContentLength()); 

InputStream input = connection.getInputStream(); 

byte[] buffer = new byte[4096]; 
int count = 0, len; 
while ((len = input.read(buffer)) > 0) { 
    count += len; 
} 

logger.debug("Got length (2): " + connection.getContentLength() + " but wanted " + count); 

आउटपुट:

Got length (1): -1 
Got length (2): -1 but wanted 30745 

ऐसा लगता है जैसे कि यह JDK6 में एक बग है, इसलिए मैं नई bug#7168608 खोला है।

  • किसी ने मुझसे मदद कर सकते हैं कोड प्रत्यक्ष FTP कनेक्शन, प्रॉक्सी और स्थानीय file:/ यूआरएल मुझे खुशी होगी के माध्यम से FTP कनेक्शन के लिए सही सामग्री का आकार लौटना चाहिए लिखने के लिए है।
  • यदि समस्या को हल नहीं किया जा सकता है- जेडीके 6 के साथ, किसी अन्य पुस्तकालय का सुझाव है जो निश्चित रूप से मैंने उल्लेख किए गए सभी मामलों के लिए काम करता है (Apache Http Client?)। जांच करने के लिए मुझे क्या करना होगा
+0

आपको सामग्री की लंबाई क्यों चाहिए? डेटा की वास्तविक धारा सही है? यदि हां, तो आपको सामग्री की लंबाई की आवश्यकता नहीं है, और सब कुछ ठीक काम कर रहा है। – jtahlborn

+0

@jtahlborn: वास्तविक यूआरएल सही है (यह सार्वजनिक एफ़टीपी है ताकि आप भी परीक्षण कर सकें)। मुझे सामग्री की लंबाई ** सीखने की आवश्यकता है ** बिना स्ट्रीम को पढ़ने के ** और इसे स्पष्ट रूप से करना संभव है। –

उत्तर

0

एक बात वास्तव में प्रतिक्रिया (मेरे सिर के ऊपर से लिख तो गलतियों उम्मीद) को पढ़ने के लिए है:

URLConnection connection= url.openConnection(); 
InputStream input= connection.getInputStream(); 
byte[] buffer= new byte[4096]; 
while(input.read(buffer) > 0) 
    ; 
logger.debug("Got length: " + getContentLength()); 

आकार मिल रहा है अच्छा है, तो देखने के लिए URLConnection को हेडर पढ़ने के लिए एक तरीका के लिए, लेकिन पूरे प्रतिक्रिया को पढ़ने से बचने के लिए डेटा नहीं।

+0

दुर्भाग्य: यह काम नहीं करता है (मेरा अद्यतन उत्तर देखें)। यदि आप किसी भी सार्वजनिक प्रॉक्सी का उपयोग करते हैं, तो आप स्वयं का परीक्षण कर सकते हैं। –

2

याद रखें कि प्रॉक्सी अक्सर अंतर्निहित इकाई के प्रतिनिधित्व को बदल देगा। आपके मामले में मुझे संदेह है कि प्रॉक्सी शायद स्थानांतरण एन्कोडिंग को बदल रहा है। जो बदले में सामग्री-लंबाई को अर्थहीन बनाता है, भले ही आपूर्ति की हो।

आप HTTP 1.1 कल्पना के निम्नलिखित दो वर्गों के afoul गिर रहे हैं:

4.4 Message Length

  1. ...
  2. ...
  3. एक सामग्री-लंबाई हेडर हैं क्षेत्र (धारा 14.13) मौजूद है, ओसीटीईटी में इसका दशमलव मान इकाई-लंबाई और स्थानांतरण-लंबाई दोनों का प्रतिनिधित्व करता है। सामग्री-लंबाई शीर्षलेख फ़ील्ड को भेजा नहीं जाना चाहिए यदि ये दो लंबाई भिन्न हैं (यानी, यदि स्थानांतरण-एन्कोडिंग हेडर फ़ील्ड मौजूद है)।यदि स्थानांतरण-एन्कोडिंग हेडर फ़ील्ड और सामग्री-लंबाई शीर्षलेख फ़ील्ड दोनों के साथ कोई संदेश प्राप्त होता है, तो बाद वाले को अनदेखा किया जाना चाहिए।

14.41 Transfer-Encoding

स्थानांतरण-एन्कोडिंग सामान्य हेडर फ़ील्ड इंगित करता है क्या परिवर्तन के प्रकार के आदेश सुरक्षित रूप से प्रेषक और प्राप्तकर्ता के बीच स्थानांतरित करने में संदेश के मुख्य भाग को लागू किया गया है (यदि हो तो)। यह सामग्री-कोडिंग से भिन्न है जिसमें स्थानांतरण-कोडिंग संदेश की एक संपत्ति है, इकाई की नहीं।

Transfer-Encoding  = "Transfer-Encoding" ":" 1#transfer-coding 

स्थानांतरण-codings खंड 3.6 में परिभाषित कर रहे हैं। एक उदाहरण है: एक से अधिक एन्कोडिंग एक इकाई के लिए लागू किया गया है

Transfer-Encoding: chunked 

हैं, तो transfer- codings वे किस क्रम में लागू किया गया में सूचीबद्ध होना चाहिए। एन्कोडिंग पैरामीटर के बारे में अतिरिक्त जानकारी अन्य विनिर्देशों द्वारा परिभाषित नहीं किए गए अन्य इकाई-हेडर फ़ील्ड द्वारा प्रदान की जा सकती है।

कई पुराने HTTP/1.0 अनुप्रयोग ट्रांसफर-एन्कोडिंग हेडर को नहीं समझते हैं।

तो URLConnection तो कल्पना के अनुसार Content-Length हैडर, अनदेखी क्योंकि यह उपस्थिति में कोई मतलब नहीं है की स्थानान्तरण

chunked अपने डिबगर स्क्रीनशॉट में यह स्पष्ट नहीं है कि क्या Transfer-Encoding हैडर मौजूद है है। कृपया हमें बताएं ...

आगे की जांच पर - ऐसा लगता है कि lynx -head जारी करते समय लिंक्स सभी शीर्षलेख वापस नहीं दिखाता है। यह इस चर्चा के लिए Transfer-Encoding हेडर महत्वपूर्ण नहीं दिखा रहा है।

यहाँ एक सार्वजनिक रूप से दृश्यमान वेबसाइट

Ξ▶ lynx -useragent='dummy' -source -head http://www.bbc.co.uk                             
HTTP/1.1 302 Found 
Server: Apache 
X-Cache-Action: PASS (non-cacheable) 
X-Cache-Age: 0 
Content-Type: text/html; charset=iso-8859-1 
Date: Tue, 03 Apr 2012 13:33:06 GMT 
Location: http://www.bbc.co.uk/mobile/ 
Connection: close 

Ξ▶ wget -useragent='dummy' -S -X HEAD http://www.bbc.co.uk                             
--2012-04-03 14:33:22-- http://www.bbc.co.uk/ 
Resolving www.bbc.co.uk... 212.58.244.70 
Connecting to www.bbc.co.uk|212.58.244.70|:80... connected. 
HTTP request sent, awaiting response... 
HTTP/1.1 200 OK 
Server: Apache 
Cache-Control: private, max-age=15 
Etag: "7e0f292b2e5e4c33cac1bc033779813b" 
Content-Type: text/html 
Transfer-Encoding: chunked 
Date: Tue, 03 Apr 2012 13:33:22 GMT 
Connection: keep-alive 
X-Cache-Action: MISS 
X-Cache-Age: 0 
X-LB-NoCache: true 
Vary: Cookie 

साथ विसंगति का सबूत अपने नेटवर्क के अंदर नहीं है के बाद से मैं कर रहा हूँ स्पष्ट रूप से मैं अपने सटीक परिस्थितियों को दोहराने नहीं कर सकता, लेकिन मान्य करें कि आप वास्तव में नहीं हैं प्रॉक्सी से गुजरते समय स्थानांतरण-एन्कोडिंग हेडर प्राप्त करना।

+0

चंकित स्थानान्तरण की उपस्थिति में यह अर्थहीन क्यों है? यदि सर्वर पूरी धारा की लंबाई को संवाद कर सकता है, तो उपभोक्ता इस जानकारी का उपयोग क्यों नहीं कर सकता? यह सभी हिस्सों को इकट्ठा करने और उपभोक्ता से इस प्रोटोकॉल विवरण को छिपाने के लिए 'URLConnection' का कार्य है। लेकिन ठीक है, अगर spec कहते हैं तो ...'Lynx' के आउटपुट से मेरे प्रश्न में आप देख सकते हैं कि 'ट्रांसफर-एन्कोडिंग' मौजूद नहीं है, इसलिए मैं आपके उत्तर के लिए वोट नहीं दे सकता। –

+0

आपके प्रश्न में lynx कमांड अजीब दिखता है। सबसे पहले '-head' http URL के लिए उपयुक्त नहीं है - दिखाया गया आदेश lynx 2.8.7rel.2 के साथ मेरे लिए काम नहीं करता है। दूसरा, आप उम्मीद करेंगे कि अगर प्रतिक्रिया प्रॉक्सी के माध्यम से होती है तो आप प्रतिक्रिया में शीर्षलेख देखेंगे। (हालांकि प्रॉक्सी हमेशा इसका सम्मान नहीं करते हैं) – sw1nn

+0

टिप्पणी के लिए धन्यवाद। मेरे द्वारा दिया गया lynx कमांड मेरे लिए ठीक काम करता है (v2.8.6rel.5 के लिए परीक्षण किया गया)। यदि आप प्रॉक्सी ** के माध्यम से ** जाते हैं तो HTTP HEAD किसी भी यूआरएल के लिए उपयुक्त है: आप इसके लिए किसी भी खुले प्रॉक्सी का प्रयास कर सकते हैं। यदि 'Via' मौजूद नहीं है, तो इसका मतलब यह नहीं है कि उत्तर प्रॉक्सी से नहीं आता है। अगर आप चाहें तो मैं 'wget' कमांड आउटपुट डाल सकता हूं, लेकिन यह समकक्ष आउटपुट का परिणाम देता है। जैसा कि मैंने उल्लेख किया है, मैं इंटरनेट पर किसी अन्य तरीके से नहीं जा सकता: फ़ायरवॉल के कारण यह संभव नहीं है। दरअसल हमारी प्रॉक्सी कॉन्फ़िगर की गई है कि क्लाइंट को 'Via' वापस न करें। 'Lynx' का आउटपुट जावा में मौजूद बिल्कुल वही है, कृपया इसे तथ्य के रूप में लें। –

1

मुझे लगता है कि यह ftp कनेक्शन को संभालने से संबंधित जेडीके में "बग" है जो प्रॉक्सीकृत हैं। प्रॉक्सी उपयोग में होने पर FtpURLConnection एक HttpURLConnection को प्रतिनिधि करता है। हालांकि, FtpURLConnection इस स्थिति में इस HttpURLConnection में किसी भी शीर्षलेख प्रबंधन को प्रतिनिधि नहीं प्रतीत होता है। इस प्रकार, आप स्ट्रीम को सही ढंग से प्राप्त कर सकते हैं, लेकिन मुझे नहीं लगता कि आप सामग्री की लंबाई या सामग्री प्रकार जैसे किसी भी "हेडर" मानों तक पहुंच सकते हैं। (यह 1.6 के लिए openjdk स्रोत पर एक त्वरित नज़र पर आधारित है, मैं कुछ याद कर सकता था)।

+0

@dma_k wrt bug jdk में - जाहिर है कि एफ़टीपी क्लाइंट कोड पूरी तरह से जेडीके 7 के लिए ओवरहाल किया गया है। http://bugs.sun.com/view_bug.do?bug_id=6893702 और http://bugs.sun.com /view_bug.do?bug_id=6519647 संबंधित प्रतीत होता है (हालांकि वास्तव में आपकी समस्या नहीं है)। क्या आपने जेडीके 7 की कोशिश की है? – sw1nn

+0

2all: यदि आप समस्या की पुष्टि करते हैं और इसे सूर्य + को लिस्नेक साझा करने की रिपोर्ट कर सकते हैं, तो मैं बक्षीस (जाने के लिए 8 घंटे) का पुरस्कार दूंगा। यहां तक ​​कि यदि समस्या जेडीके 7 में तय की गई है (मैंने चेक नहीं किया है), तो मुझे इसका लाभ नहीं हो सकता है: उत्पादन एएस जावा 6 में है और अगले कुछ सालों में होगा। इससे भी बदतर: कोड 1.5 अनुपालन होना चाहिए। –

+1

@dma_k - यह आपकी समस्या की पुष्टि करने के लिए हर किसी का काम क्यों है? मैंने आपको दिया जो मुझे विश्वास है कि सही जवाब है। इसकी पुष्टि करने के लिए आपके लिए बहुत आसान होना चाहिए। – jtahlborn