/[classpath]/inetlib/source/gnu/inet/http/Request.java
ViewVC logotype

Diff of /inetlib/source/gnu/inet/http/Request.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.13 by dog, Thu Nov 25 12:45:43 2004 UTC revision 1.14 by dog, Thu Nov 25 22:15:05 2004 UTC
# Line 1  Line 1 
1  /*  /*
2   * $Id$   * Request.java
3   * Copyright (C) 2004 The Free Software Foundation   * Copyright (C) 2004 The Free Software Foundation
4   *   *
5   * This file is part of GNU inetlib, a library.   * This file is part of GNU inetlib, a library.
# Line 126  public class Request Line 126  public class Request
126     * @param method the HTTP method     * @param method the HTTP method
127     * @param path the resource path including query part     * @param path the resource path including query part
128     */     */
129    protected Request (HTTPConnection connection, String method,    protected Request(HTTPConnection connection, String method,
130                       String path)                      String path)
131    {    {
132      this.connection = connection;      this.connection = connection;
133      this.method = method;      this.method = method;
134      this.path = path;      this.path = path;
135      requestHeaders = new Headers ();      requestHeaders = new Headers();
136      responseHeaderHandlers = new HashMap ();      responseHeaderHandlers = new HashMap();
137      requestBodyNegotiationThreshold = 4096;      requestBodyNegotiationThreshold = 4096;
138    }    }
139    
# Line 141  public class Request Line 141  public class Request
141     * Returns the connection associated with this request.     * Returns the connection associated with this request.
142     * @see #connection     * @see #connection
143     */     */
144    public HTTPConnection getConnection ()    public HTTPConnection getConnection()
145    {    {
146      return connection;      return connection;
147    }    }
# Line 150  public class Request Line 150  public class Request
150     * Returns the HTTP method to invoke.     * Returns the HTTP method to invoke.
151     * @see #method     * @see #method
152     */     */
153    public String getMethod ()    public String getMethod()
154    {    {
155      return method;      return method;
156    }    }
# Line 159  public class Request Line 159  public class Request
159     * Returns the resource path.     * Returns the resource path.
160     * @see #path     * @see #path
161     */     */
162    public String getPath ()    public String getPath()
163    {    {
164      return path;      return path;
165    }    }
# Line 168  public class Request Line 168  public class Request
168     * Returns the full request-URI represented by this request, as specified     * Returns the full request-URI represented by this request, as specified
169     * by HTTP/1.1.     * by HTTP/1.1.
170     */     */
171    public String getRequestURI ()    public String getRequestURI()
172    {    {
173      return connection.getURI () + path;      return connection.getURI() + path;
174    }    }
175    
176    /**    /**
177     * Returns the headers in this request.     * Returns the headers in this request.
178     */     */
179    public Headers getHeaders ()    public Headers getHeaders()
180    {    {
181      return requestHeaders;      return requestHeaders;
182    }    }
# Line 185  public class Request Line 185  public class Request
185     * Returns the value of the specified header in this request.     * Returns the value of the specified header in this request.
186     * @param name the header name     * @param name the header name
187     */     */
188    public String getHeader (String name)    public String getHeader(String name)
189    {    {
190      return requestHeaders.getValue (name);      return requestHeaders.getValue(name);
191    }    }
192    
193    /**    /**
194     * Returns the value of the specified header in this request as an integer.     * Returns the value of the specified header in this request as an integer.
195     * @param name the header name     * @param name the header name
196     */     */
197    public int getIntHeader (String name)    public int getIntHeader(String name)
198    {    {
199      return requestHeaders.getIntValue (name);      return requestHeaders.getIntValue(name);
200    }    }
201    
202    /**    /**
203     * Returns the value of the specified header in this request as a date.     * Returns the value of the specified header in this request as a date.
204     * @param name the header name     * @param name the header name
205     */     */
206    public Date getDateHeader (String name)    public Date getDateHeader(String name)
207    {    {
208      return requestHeaders.getDateValue (name);      return requestHeaders.getDateValue(name);
209    }    }
210    
211    /**    /**
# Line 213  public class Request Line 213  public class Request
213     * @param name the header name     * @param name the header name
214     * @param value the header value     * @param value the header value
215     */     */
216    public void setHeader (String name, String value)    public void setHeader(String name, String value)
217    {    {
218      requestHeaders.put (name, value);      requestHeaders.put(name, value);
219    }    }
220    
221    /**    /**
222     * Convenience method to set the entire request body.     * Convenience method to set the entire request body.
223     * @param requestBody the request body content     * @param requestBody the request body content
224     */     */
225    public void setRequestBody (byte[] requestBody)    public void setRequestBody(byte[] requestBody)
226    {    {
227      setRequestBodyWriter (new ByteArrayRequestBodyWriter (requestBody));      setRequestBodyWriter(new ByteArrayRequestBodyWriter(requestBody));
228    }    }
229    
230    /**    /**
231     * Sets the request body provider.     * Sets the request body provider.
232     * @param requestBodyWriter the handler used to obtain the request body     * @param requestBodyWriter the handler used to obtain the request body
233     */     */
234    public void setRequestBodyWriter (RequestBodyWriter requestBodyWriter)    public void setRequestBodyWriter(RequestBodyWriter requestBodyWriter)
235    {    {
236      this.requestBodyWriter = requestBodyWriter;      this.requestBodyWriter = requestBodyWriter;
237    }    }
# Line 241  public class Request Line 241  public class Request
241     * @param responseBodyReader the handler to receive notifications of     * @param responseBodyReader the handler to receive notifications of
242     * response body content     * response body content
243     */     */
244    public void setResponseBodyReader (ResponseBodyReader responseBodyReader)    public void setResponseBodyReader(ResponseBodyReader responseBodyReader)
245    {    {
246      this.responseBodyReader = responseBodyReader;      this.responseBodyReader = responseBodyReader;
247    }    }
# Line 251  public class Request Line 251  public class Request
251     * @param name the header name     * @param name the header name
252     * @param handler the handler to receive the value for the header     * @param handler the handler to receive the value for the header
253     */     */
254    public void setResponseHeaderHandler (String name,    public void setResponseHeaderHandler(String name,
255                                          ResponseHeaderHandler handler)                                         ResponseHeaderHandler handler)
256    {    {
257      responseHeaderHandlers.put (name, handler);      responseHeaderHandlers.put(name, handler);
258    }    }
259    
260    /**    /**
# Line 262  public class Request Line 262  public class Request
262     * automatically.     * automatically.
263     * @param authenticator the authenticator     * @param authenticator the authenticator
264     */     */
265    public void setAuthenticator (Authenticator authenticator)    public void setAuthenticator(Authenticator authenticator)
266    {    {
267      this.authenticator = authenticator;      this.authenticator = authenticator;
268    }    }
# Line 270  public class Request Line 270  public class Request
270    /**    /**
271     * Sets the request body negotiation threshold.     * Sets the request body negotiation threshold.
272     * If this is set, it determines the maximum size that the request body     * If this is set, it determines the maximum size that the request body
273     * may be before body negotiation occurs (via the     * may be before body negotiation occurs(via the
274     * <code>100-continue</code> expectation). This ensures that a large     * <code>100-continue</code> expectation). This ensures that a large
275     * request body is not sent when the server wouldn't have accepted it     * request body is not sent when the server wouldn't have accepted it
276     * anyway.     * anyway.
277     * @param threshold the body negotiation threshold, or &lt;=0 to disable     * @param threshold the body negotiation threshold, or &lt;=0 to disable
278     * request body negotation entirely     * request body negotation entirely
279     */     */
280    public void setRequestBodyNegotiationThreshold (int threshold)    public void setRequestBodyNegotiationThreshold(int threshold)
281    {    {
282      requestBodyNegotiationThreshold = threshold;      requestBodyNegotiationThreshold = threshold;
283    }    }
# Line 289  public class Request Line 289  public class Request
289     * @exception IOException if an I/O error occurred     * @exception IOException if an I/O error occurred
290     * @return an HTTP response object representing the result of the operation     * @return an HTTP response object representing the result of the operation
291     */     */
292    public Response dispatch ()    public Response dispatch()
293      throws IOException      throws IOException
294    {    {
295      if (dispatched)      if (dispatched)
296        {        {
297          throw new ProtocolException ("request already dispatched");          throw new ProtocolException("request already dispatched");
298        }        }
299      final String CRLF = "\r\n";      final String CRLF = "\r\n";
300      final String HEADER_SEP = ": ";      final String HEADER_SEP = ": ";
301      final String US_ASCII = "US-ASCII";      final String US_ASCII = "US-ASCII";
302      final String version = connection.getVersion ();      final String version = connection.getVersion();
303      Response response;      Response response;
304      int contentLength = -1;      int contentLength = -1;
305      boolean retry = false;      boolean retry = false;
# Line 307  public class Request Line 307  public class Request
307      boolean expectingContinue = false;      boolean expectingContinue = false;
308      if (requestBodyWriter != null)      if (requestBodyWriter != null)
309        {        {
310          contentLength = requestBodyWriter.getContentLength ();          contentLength = requestBodyWriter.getContentLength();
311          if (contentLength > requestBodyNegotiationThreshold)          if (contentLength > requestBodyNegotiationThreshold)
312            {            {
313              expectingContinue = true;              expectingContinue = true;
314              setHeader ("Expect", "100-continue");              setHeader("Expect", "100-continue");
315            }            }
316          else          else
317            {            {
318              setHeader ("Content-Length", Integer.toString (contentLength));              setHeader("Content-Length", Integer.toString(contentLength));
319            }            }
320        }        }
321            
# Line 326  public class Request Line 326  public class Request
326            {            {
327              retry = false;              retry = false;
328              // Send request              // Send request
329              connection.fireRequestEvent (RequestEvent.REQUEST_SENDING, this);              connection.fireRequestEvent(RequestEvent.REQUEST_SENDING, this);
330                            
331              // Get socket output and input streams              // Get socket output and input streams
332              OutputStream out = connection.getOutputStream ();              OutputStream out = connection.getOutputStream();
333              LineInputStream in =              LineInputStream in =
334                new LineInputStream (connection.getInputStream ());                new LineInputStream(connection.getInputStream());
335              // Request line              // Request line
336              String requestUri = path;              String requestUri = path;
337              if (connection.isUsingProxy () &&              if (connection.isUsingProxy() &&
338                  !"*".equals (requestUri) &&                  !"*".equals(requestUri) &&
339                  !"CONNECT".equals (method))                  !"CONNECT".equals(method))
340                {                {
341                  requestUri = getRequestURI ();                  requestUri = getRequestURI();
342                }                }
343              String line = method + ' ' + requestUri + ' ' + version + CRLF;              String line = method + ' ' + requestUri + ' ' + version + CRLF;
344              out.write (line.getBytes (US_ASCII));              out.write(line.getBytes(US_ASCII));
345              // Request headers              // Request headers
346              for (Iterator i = requestHeaders.keySet ().iterator ();              for (Iterator i = requestHeaders.keySet().iterator();
347                   i.hasNext (); )                   i.hasNext(); )
348                {                {
349                  String name = (String) i.next ();                  String name =(String) i.next();
350                  String value = (String) requestHeaders.get (name);                  String value =(String) requestHeaders.get(name);
351                  line = name + HEADER_SEP + value + CRLF;                  line = name + HEADER_SEP + value + CRLF;
352                  out.write (line.getBytes (US_ASCII));                  out.write(line.getBytes(US_ASCII));
353                }                }
354              out.write (CRLF.getBytes (US_ASCII));              out.write(CRLF.getBytes(US_ASCII));
355              // Request body              // Request body
356              if (requestBodyWriter != null && !expectingContinue)              if (requestBodyWriter != null && !expectingContinue)
357                {                {
# Line 359  public class Request Line 359  public class Request
359                  int len;                  int len;
360                  int count = 0;                  int count = 0;
361                                    
362                  requestBodyWriter.reset ();                  requestBodyWriter.reset();
363                  do                  do
364                    {                    {
365                      len = requestBodyWriter.write (buffer);                      len = requestBodyWriter.write(buffer);
366                      if (len > 0)                      if (len > 0)
367                        {                        {
368                          out.write (buffer, 0, len);                          out.write(buffer, 0, len);
369                        }                        }
370                      count += len;                      count += len;
371                    }                    }
372                  while (len > -1 && count < contentLength);                  while (len > -1 && count < contentLength);
373                  out.write (CRLF.getBytes (US_ASCII));                  out.write(CRLF.getBytes(US_ASCII));
374                }                }
375              out.flush ();              out.flush();
376              // Sent event              // Sent event
377              connection.fireRequestEvent (RequestEvent.REQUEST_SENT, this);              connection.fireRequestEvent(RequestEvent.REQUEST_SENT, this);
378              // Get response              // Get response
379              response = readResponse (in);              response = readResponse(in);
380              int sc = response.getCode ();              int sc = response.getCode();
381              if (sc == 401 && authenticator != null)              if (sc == 401 && authenticator != null)
382                {                {
383                  if (authenticate (response, attempts++))                  if (authenticate(response, attempts++))
384                    {                    {
385                      retry = true;                      retry = true;
386                    }                    }
387                }                }
388              else if (sc == 100 && expectingContinue)              else if (sc == 100 && expectingContinue)
389                {                {
390                  requestHeaders.remove ("Expect");                  requestHeaders.remove("Expect");
391                  setHeader ("Content-Length", Integer.toString (contentLength));                  setHeader("Content-Length", Integer.toString(contentLength));
392                  expectingContinue = false;                  expectingContinue = false;
393                  retry = true;                  retry = true;
394                }                }
# Line 397  public class Request Line 397  public class Request
397        }        }
398      catch (IOException e)      catch (IOException e)
399        {        {
400          connection.close ();          connection.close();
401          throw e;          throw e;
402        }        }
403      return response;      return response;
404    }    }
405            
406    Response readResponse (LineInputStream in)    Response readResponse(LineInputStream in)
407      throws IOException      throws IOException
408    {    {
409      String line;      String line;
410      int len;      int len;
411            
412      // Read response status line      // Read response status line
413      line = in.readLine ();      line = in.readLine();
414      if (line == null)      if (line == null)
415        {        {
416          throw new ProtocolException ("Peer closed connection");          throw new ProtocolException("Peer closed connection");
417        }        }
418      if (!line.startsWith ("HTTP/"))      if (!line.startsWith("HTTP/"))
419        {        {
420          throw new ProtocolException (line);          throw new ProtocolException(line);
421        }        }
422      len = line.length ();      len = line.length();
423      int start = 5, end = 6;      int start = 5, end = 6;
424      while (line.charAt (end) != '.')      while (line.charAt(end) != '.')
425        {        {
426          end++;          end++;
427        }        }
428      int majorVersion = Integer.parseInt (line.substring (start, end));      int majorVersion = Integer.parseInt(line.substring(start, end));
429      start = end + 1;      start = end + 1;
430      end = start + 1;      end = start + 1;
431      while (line.charAt (end) != ' ')      while (line.charAt(end) != ' ')
432        {        {
433          end++;          end++;
434        }        }
435      int minorVersion = Integer.parseInt (line.substring (start, end));      int minorVersion = Integer.parseInt(line.substring(start, end));
436      start = end + 1;      start = end + 1;
437      end = start + 3;      end = start + 3;
438      int code = Integer.parseInt (line.substring (start, end));      int code = Integer.parseInt(line.substring(start, end));
439      String message = line.substring (end + 1, len - 1);      String message = line.substring(end + 1, len - 1);
440      // Read response headers      // Read response headers
441      Headers responseHeaders = new Headers ();      Headers responseHeaders = new Headers();
442      responseHeaders.parse (in);      responseHeaders.parse(in);
443      notifyHeaderHandlers (responseHeaders);      notifyHeaderHandlers(responseHeaders);
444      // Construct response      // Construct response
445      int codeClass = code / 100;      int codeClass = code / 100;
446      Response ret = new Response (majorVersion, minorVersion, code,      Response ret = new Response(majorVersion, minorVersion, code,
447                                   codeClass, message, responseHeaders);                                  codeClass, message, responseHeaders);
448      switch (code)      switch (code)
449        {        {
450        case 204:        case 204:
# Line 455  public class Request Line 455  public class Request
455          boolean notify = (responseBodyReader != null);          boolean notify = (responseBodyReader != null);
456          if (notify)          if (notify)
457            {            {
458              if (!responseBodyReader.accept (this, ret))              if (!responseBodyReader.accept(this, ret))
459                {                {
460                  notify = false;                  notify = false;
461                }                }
462            }            }
463          readResponseBody (ret, in, notify);          readResponseBody(ret, in, notify);
464        }        }
465      return ret;      return ret;
466    }    }
467    
468    void notifyHeaderHandlers (Headers headers)    void notifyHeaderHandlers(Headers headers)
469    {    {
470      for (Iterator i = headers.entrySet ().iterator (); i.hasNext (); )      for (Iterator i = headers.entrySet().iterator(); i.hasNext(); )
471        {        {
472          Map.Entry entry = (Map.Entry) i.next ();          Map.Entry entry = (Map.Entry) i.next();
473          String name = (String) entry.getKey ();          String name =(String) entry.getKey();
474          // Handle Set-Cookie          // Handle Set-Cookie
475          if ("Set-Cookie".equalsIgnoreCase (name))          if ("Set-Cookie".equalsIgnoreCase(name))
476            {            {
477              String value = (String) entry.getValue ();              String value = (String) entry.getValue();
478              handleSetCookie (value);              handleSetCookie(value);
479            }            }
480          ResponseHeaderHandler handler =          ResponseHeaderHandler handler =
481            (ResponseHeaderHandler) responseHeaderHandlers.get (name);            (ResponseHeaderHandler) responseHeaderHandlers.get(name);
482          if (handler != null)          if (handler != null)
483            {            {
484              String value = (String) entry.getValue ();              String value = (String) entry.getValue();
485              handler.setValue (value);              handler.setValue(value);
486            }            }
487        }        }
488    }    }
489    
490    void readResponseBody (Response response, InputStream in,    void readResponseBody(Response response, InputStream in,
491                           boolean notify)                          boolean notify)
492      throws IOException      throws IOException
493    {    {
494      byte[] buffer = new byte[4096];      byte[] buffer = new byte[4096];
495      int contentLength = -1;      int contentLength = -1;
496      Headers trailer = null;      Headers trailer = null;
497            
498      String transferCoding = response.getHeader ("Transfer-Encoding");      String transferCoding = response.getHeader("Transfer-Encoding");
499      if ("chunked".equalsIgnoreCase (transferCoding))      if ("chunked".equalsIgnoreCase(transferCoding))
500        {        {
501          trailer = new Headers ();          trailer = new Headers();
502          in = new ChunkedInputStream (in, trailer);          in = new ChunkedInputStream(in, trailer);
503        }        }
504      else      else
505        {        {
506          contentLength = response.getIntHeader ("Content-Length");          contentLength = response.getIntHeader("Content-Length");
507        }        }
508      String contentCoding = response.getHeader ("Content-Encoding");      String contentCoding = response.getHeader("Content-Encoding");
509      if (contentCoding != null && !"identity".equals (contentCoding))      if (contentCoding != null && !"identity".equals(contentCoding))
510        {        {
511          if ("gzip".equals (contentCoding))          if ("gzip".equals(contentCoding))
512            {            {
513              in = new GZIPInputStream (in);              in = new GZIPInputStream(in);
514            }            }
515          else if ("deflate".equals (contentCoding))          else if ("deflate".equals(contentCoding))
516            {            {
517              in = new InflaterInputStream (in);              in = new InflaterInputStream(in);
518            }            }
519          else          else
520            {            {
521              throw new ProtocolException ("Unsupported Content-Encoding: " +              throw new ProtocolException("Unsupported Content-Encoding: " +
522                                           contentCoding);                                          contentCoding);
523            }            }
524        }        }
525            
526      // Persistent connections are the default in HTTP/1.1      // Persistent connections are the default in HTTP/1.1
527      boolean doClose = "close".equalsIgnoreCase (getHeader ("Connection")) ||      boolean doClose = "close".equalsIgnoreCase(getHeader("Connection")) ||
528        "close".equalsIgnoreCase (response.getHeader ("Connection")) ||        "close".equalsIgnoreCase(response.getHeader("Connection")) ||
529        (connection.majorVersion == 1 && connection.minorVersion == 0) ||        (connection.majorVersion == 1 && connection.minorVersion == 0) ||
530        (response.majorVersion == 1 && response.minorVersion == 0);        (response.majorVersion == 1 && response.minorVersion == 0);
531            
# Line 534  public class Request Line 534  public class Request
534      len = (len > buffer.length) ? buffer.length : len;      len = (len > buffer.length) ? buffer.length : len;
535      while (len > -1)      while (len > -1)
536        {        {
537          len = in.read (buffer, 0, len);          len = in.read(buffer, 0, len);
538          if (len < 0)          if (len < 0)
539            {            {
540              // EOF              // EOF
541              connection.closeConnection ();              connection.closeConnection();
542              break;              break;
543            }            }
544          if (notify)          if (notify)
545            {            {
546              responseBodyReader.read (buffer, 0, len);              responseBodyReader.read(buffer, 0, len);
547            }            }
548          if (count > -1)          if (count > -1)
549            {            {
# Line 552  public class Request Line 552  public class Request
552                {                {
553                  if (doClose)                  if (doClose)
554                    {                    {
555                      connection.closeConnection ();                      connection.closeConnection();
556                    }                    }
557                  break;                  break;
558                }                }
# Line 560  public class Request Line 560  public class Request
560        }        }
561      if (notify)      if (notify)
562        {        {
563          responseBodyReader.close ();          responseBodyReader.close();
564        }        }
565      if (trailer != null)      if (trailer != null)
566        {        {
567          response.getHeaders ().putAll (trailer);          response.getHeaders().putAll(trailer);
568          notifyHeaderHandlers (trailer);          notifyHeaderHandlers(trailer);
569        }        }
570    }    }
571    
572    boolean authenticate (Response response, int attempts)    boolean authenticate(Response response, int attempts)
573      throws IOException      throws IOException
574    {    {
575      String challenge = response.getHeader ("WWW-Authenticate");      String challenge = response.getHeader("WWW-Authenticate");
576      if (challenge == null)      if (challenge == null)
577        {        {
578          challenge = response.getHeader ("Proxy-Authenticate");          challenge = response.getHeader("Proxy-Authenticate");
579        }        }
580      int si = challenge.indexOf (' ');      int si = challenge.indexOf(' ');
581      String scheme = (si == -1) ? challenge : challenge.substring (0, si);      String scheme = (si == -1) ? challenge : challenge.substring(0, si);
582      if ("Basic".equalsIgnoreCase (scheme))      if ("Basic".equalsIgnoreCase(scheme))
583        {        {
584          Properties params = parseAuthParams (challenge.substring (si + 1));          Properties params = parseAuthParams(challenge.substring(si + 1));
585          String realm = params.getProperty ("realm");          String realm = params.getProperty("realm");
586          Credentials creds = authenticator.getCredentials (realm, attempts);          Credentials creds = authenticator.getCredentials(realm, attempts);
587          String userPass = creds.getUsername () + ':' + creds.getPassword ();          String userPass = creds.getUsername() + ':' + creds.getPassword();
588          byte[] b_userPass = userPass.getBytes ("US-ASCII");          byte[] b_userPass = userPass.getBytes("US-ASCII");
589          byte[] b_encoded = BASE64.encode (b_userPass);          byte[] b_encoded = BASE64.encode(b_userPass);
590          String authorization =          String authorization =
591            scheme + " " + new String (b_encoded, "US-ASCII");            scheme + " " + new String(b_encoded, "US-ASCII");
592          setHeader ("Authorization", authorization);          setHeader("Authorization", authorization);
593          return true;          return true;
594        }        }
595      else if ("Digest".equalsIgnoreCase (scheme))      else if ("Digest".equalsIgnoreCase(scheme))
596        {        {
597          Properties params = parseAuthParams (challenge.substring (si + 1));          Properties params = parseAuthParams(challenge.substring(si + 1));
598          String realm = params.getProperty ("realm");          String realm = params.getProperty("realm");
599          String nonce = params.getProperty ("nonce");          String nonce = params.getProperty("nonce");
600          String qop = params.getProperty ("qop");          String qop = params.getProperty("qop");
601          String algorithm = params.getProperty ("algorithm");          String algorithm = params.getProperty("algorithm");
602          String digestUri = getRequestURI ();          String digestUri = getRequestURI();
603          Credentials creds = authenticator.getCredentials (realm, attempts);          Credentials creds = authenticator.getCredentials(realm, attempts);
604          String username = creds.getUsername ();          String username = creds.getUsername();
605          String password = creds.getPassword ();          String password = creds.getPassword();
606          connection.incrementNonce (nonce);          connection.incrementNonce(nonce);
607          try          try
608            {            {
609              MessageDigest md5 = MessageDigest.getInstance ("MD5");              MessageDigest md5 = MessageDigest.getInstance("MD5");
610              final byte[] COLON = { 0x3a };              final byte[] COLON = { 0x3a };
611                            
612              // Calculate H(A1)              // Calculate H(A1)
613              md5.reset ();              md5.reset();
614              md5.update (username.getBytes ("US-ASCII"));              md5.update(username.getBytes("US-ASCII"));
615              md5.update (COLON);              md5.update(COLON);
616              md5.update (realm.getBytes ("US-ASCII"));              md5.update(realm.getBytes("US-ASCII"));
617              md5.update (COLON);              md5.update(COLON);
618              md5.update (password.getBytes ("US-ASCII"));              md5.update(password.getBytes("US-ASCII"));
619              byte[] ha1 = md5.digest ();              byte[] ha1 = md5.digest();
620              if ("md5-sess".equals (algorithm))              if ("md5-sess".equals(algorithm))
621                {                {
622                  byte[] cnonce = generateNonce ();                  byte[] cnonce = generateNonce();
623                  md5.reset ();                  md5.reset();
624                  md5.update (ha1);                  md5.update(ha1);
625                  md5.update (COLON);                  md5.update(COLON);
626                  md5.update (nonce.getBytes ("US-ASCII"));                  md5.update(nonce.getBytes("US-ASCII"));
627                  md5.update (COLON);                  md5.update(COLON);
628                  md5.update (cnonce);                  md5.update(cnonce);
629                  ha1 = md5.digest();                  ha1 = md5.digest();
630                }                }
631              String ha1Hex = toHexString (ha1);              String ha1Hex = toHexString(ha1);
632                            
633              // Calculate H(A2)              // Calculate H(A2)
634              md5.reset ();              md5.reset();
635              md5.update (method.getBytes ("US-ASCII"));              md5.update(method.getBytes("US-ASCII"));
636              md5.update (COLON);              md5.update(COLON);
637              md5.update (digestUri.getBytes ("US-ASCII"));              md5.update(digestUri.getBytes("US-ASCII"));
638              if ("auth-int".equals (qop))              if ("auth-int".equals(qop))
639                {                {
640                  byte[] hEntity = null; // TODO hash of entity body                  byte[] hEntity = null; // TODO hash of entity body
641                  md5.update (COLON);                  md5.update(COLON);
642                  md5.update (hEntity);                  md5.update(hEntity);
643                }                }
644              byte[] ha2 = md5.digest ();              byte[] ha2 = md5.digest();
645              String ha2Hex = toHexString (ha2);              String ha2Hex = toHexString(ha2);
646                            
647              // Calculate response              // Calculate response
648              md5.reset ();              md5.reset();
649              md5.update (ha1Hex.getBytes ("US-ASCII"));              md5.update(ha1Hex.getBytes("US-ASCII"));
650              md5.update (COLON);              md5.update(COLON);
651              md5.update (nonce.getBytes ("US-ASCII"));              md5.update(nonce.getBytes("US-ASCII"));
652              if ("auth".equals (qop) || "auth-int".equals (qop))              if ("auth".equals(qop) || "auth-int".equals(qop))
653                {                {
654                  String nc = getNonceCount (nonce);                  String nc = getNonceCount(nonce);
655                  byte[] cnonce = generateNonce ();                  byte[] cnonce = generateNonce();
656                  md5.update (COLON);                  md5.update(COLON);
657                  md5.update (nc.getBytes ("US-ASCII"));                  md5.update(nc.getBytes("US-ASCII"));
658                  md5.update (COLON);                  md5.update(COLON);
659                  md5.update (cnonce);                  md5.update(cnonce);
660                  md5.update (COLON);                  md5.update(COLON);
661                  md5.update (qop.getBytes ("US-ASCII"));                  md5.update(qop.getBytes("US-ASCII"));
662                }                }
663              md5.update (COLON);              md5.update(COLON);
664              md5.update (ha2Hex.getBytes ("US-ASCII"));              md5.update(ha2Hex.getBytes("US-ASCII"));
665              String digestResponse = toHexString (md5.digest ());              String digestResponse = toHexString(md5.digest());
666                            
667              String authorization = scheme +              String authorization = scheme +
668                " username=\"" + username + "\"" +                " username=\"" + username + "\"" +
# Line 670  public class Request Line 670  public class Request
670                " nonce=\"" + nonce + "\"" +                " nonce=\"" + nonce + "\"" +
671                " uri=\"" + digestUri + "\"" +                " uri=\"" + digestUri + "\"" +
672                " response=\"" + digestResponse + "\"";                " response=\"" + digestResponse + "\"";
673              setHeader ("Authorization", authorization);              setHeader("Authorization", authorization);
674              return true;              return true;
675            }            }
676          catch (NoSuchAlgorithmException e)          catch (NoSuchAlgorithmException e)
# Line 682  public class Request Line 682  public class Request
682      return false;      return false;
683    }    }
684    
685    Properties parseAuthParams (String text)    Properties parseAuthParams(String text)
686    {    {
687      int len = text.length ();      int len = text.length();
688      String key = null;      String key = null;
689      StringBuffer buf = new StringBuffer ();      StringBuffer buf = new StringBuffer();
690      Properties ret = new Properties ();      Properties ret = new Properties();
691      boolean inQuote = false;      boolean inQuote = false;
692      for (int i = 0; i < len; i++)      for (int i = 0; i < len; i++)
693        {        {
694          char c = text.charAt (i);          char c = text.charAt(i);
695          if (c == '"')          if (c == '"')
696            {            {
697              inQuote = !inQuote;              inQuote = !inQuote;
698            }            }
699          else if (c == '=' && key == null)          else if (c == '=' && key == null)
700            {            {
701              key = buf.toString ().trim ();              key = buf.toString().trim();
702              buf.setLength (0);              buf.setLength(0);
703            }            }
704          else if (c == ' ' && !inQuote)          else if (c == ' ' && !inQuote)
705            {            {
706              String value = unquote (buf.toString ().trim ());              String value = unquote(buf.toString().trim());
707              ret.put (key, value);              ret.put(key, value);
708              key = null;              key = null;
709              buf.setLength (0);              buf.setLength(0);
710            }            }
711          else if (c != ',' || (i < (len - 1) && text.charAt (i + 1) != ' '))          else if (c != ',' || (i <(len - 1) && text.charAt(i + 1) != ' '))
712            {              {  
713              buf.append (c);              buf.append(c);
714            }            }
715        }        }
716      if (key != null)      if (key != null)
717        {        {
718          String value = unquote (buf.toString ().trim ());          String value = unquote(buf.toString().trim());
719          ret.put (key, value);          ret.put(key, value);
720        }        }
721      return ret;      return ret;
722    }    }
723    
724    String unquote (String text)    String unquote(String text)
725    {    {
726      int len = text.length ();      int len = text.length();
727      if (len > 0 && text.charAt (0) == '"' && text.charAt (len - 1) == '"')      if (len > 0 && text.charAt(0) == '"' && text.charAt(len - 1) == '"')
728        {        {
729          return text.substring (1, len - 1);          return text.substring(1, len - 1);
730        }        }
731      return text;      return text;
732    }    }
# Line 735  public class Request Line 735  public class Request
735     * Returns the number of times the specified nonce value has been seen.     * Returns the number of times the specified nonce value has been seen.
736     * This always returns an 8-byte 0-padded hexadecimal string.     * This always returns an 8-byte 0-padded hexadecimal string.
737     */     */
738    String getNonceCount (String nonce)    String getNonceCount(String nonce)
739    {    {
740      int nc = connection.getNonceCount (nonce);      int nc = connection.getNonceCount(nonce);
741      String hex = Integer.toHexString (nc);      String hex = Integer.toHexString(nc);
742      StringBuffer buf = new StringBuffer ();      StringBuffer buf = new StringBuffer();
743      for (int i = 8 - hex.length (); i > 0; i--)      for (int i = 8 - hex.length(); i > 0; i--)
744        {        {
745          buf.append ('0');          buf.append('0');
746        }        }
747      buf.append (hex);      buf.append(hex);
748      return buf.toString ();      return buf.toString();
749    }    }
750    
751    /**    /**
# Line 756  public class Request Line 756  public class Request
756    /**    /**
757     * Generates a new client nonce value.     * Generates a new client nonce value.
758     */     */
759    byte[] generateNonce ()    byte[] generateNonce()
760      throws IOException, NoSuchAlgorithmException      throws IOException, NoSuchAlgorithmException
761    {    {
762      if (nonce == null)      if (nonce == null)
763        {        {
764          long time = System.currentTimeMillis ();          long time = System.currentTimeMillis();
765          MessageDigest md5 = MessageDigest.getInstance ("MD5");          MessageDigest md5 = MessageDigest.getInstance("MD5");
766          md5.update (Long.toString (time).getBytes ("US-ASCII"));          md5.update(Long.toString(time).getBytes("US-ASCII"));
767          nonce = md5.digest ();          nonce = md5.digest();
768        }        }
769      return nonce;      return nonce;
770    }    }
771    
772    String toHexString (byte[] bytes)    String toHexString(byte[] bytes)
773    {    {
774      char[] ret = new char[bytes.length * 2];      char[] ret = new char[bytes.length * 2];
775      for (int i = 0, j = 0; i < bytes.length; i++)      for (int i = 0, j = 0; i < bytes.length; i++)
776        {        {
777          int c = (int) bytes[i];          int c =(int) bytes[i];
778          if (c < 0)          if (c < 0)
779            {            {
780              c += 0x100;              c += 0x100;
781            }            }
782          ret[j++] = Character.forDigit (c / 0x10, 0x10);          ret[j++] = Character.forDigit(c / 0x10, 0x10);
783          ret[j++] = Character.forDigit (c % 0x10, 0x10);          ret[j++] = Character.forDigit(c % 0x10, 0x10);
784        }        }
785      return new String (ret);      return new String(ret);
786    }    }
787    
788    /**    /**
789     * Parse the specified cookie list and notify the cookie manager.     * Parse the specified cookie list and notify the cookie manager.
790     */     */
791    void handleSetCookie (String text)    void handleSetCookie(String text)
792    {    {
793      CookieManager cookieManager = connection.getCookieManager ();      CookieManager cookieManager = connection.getCookieManager();
794      if (cookieManager == null)      if (cookieManager == null)
795        {        {
796          return;          return;
# Line 798  public class Request Line 798  public class Request
798      String name = null;      String name = null;
799      String value = null;      String value = null;
800      String comment = null;      String comment = null;
801      String domain = connection.getHostName ();      String domain = connection.getHostName();
802      String path = this.path;      String path = this.path;
803      int lsi = path.lastIndexOf ('/');      int lsi = path.lastIndexOf('/');
804      if (lsi != -1)      if (lsi != -1)
805        {        {
806          path = path.substring (0, lsi);          path = path.substring(0, lsi);
807        }        }
808      boolean secure = false;      boolean secure = false;
809      Date expires = null;      Date expires = null;
810    
811      int len = text.length ();      int len = text.length();
812      String attr = null;      String attr = null;
813      StringBuffer buf = new StringBuffer ();      StringBuffer buf = new StringBuffer();
814      boolean inQuote = false;      boolean inQuote = false;
815      for (int i = 0; i <= len; i++)      for (int i = 0; i <= len; i++)
816        {        {
817          char c = (i == len) ? '\u0000' : text.charAt (i);          char c =(i == len) ? '\u0000' : text.charAt(i);
818          if (c == '"')          if (c == '"')
819            {            {
820              inQuote = !inQuote;              inQuote = !inQuote;
# Line 823  public class Request Line 823  public class Request
823            {            {
824              if (c == '=' && attr == null)              if (c == '=' && attr == null)
825                {                {
826                  attr = buf.toString ().trim ();                  attr = buf.toString().trim();
827                  buf.setLength (0);                  buf.setLength(0);
828                }                }
829              else if (c == ';' || i == len || c == ',')              else if (c == ';' || i == len || c == ',')
830                {                {
831                  String val = unquote (buf.toString ().trim ());                  String val = unquote(buf.toString().trim());
832                  if (name == null)                  if (name == null)
833                    {                    {
834                      name = attr;                      name = attr;
835                      value = val;                      value = val;
836                    }                    }
837                  else if ("Comment".equalsIgnoreCase (attr))                  else if ("Comment".equalsIgnoreCase(attr))
838                    {                    {
839                      comment = val;                      comment = val;
840                    }                    }
841                  else if ("Domain".equalsIgnoreCase (attr))                  else if ("Domain".equalsIgnoreCase(attr))
842                    {                    {
843                      domain = val;                      domain = val;
844                    }                    }
845                  else if ("Path".equalsIgnoreCase (attr))                  else if ("Path".equalsIgnoreCase(attr))
846                    {                    {
847                      path = val;                      path = val;
848                    }                    }
849                  else if ("Secure".equalsIgnoreCase (val))                  else if ("Secure".equalsIgnoreCase(val))
850                    {                    {
851                      secure = true;                      secure = true;
852                    }                    }
853                  else if ("Max-Age".equalsIgnoreCase (attr))                  else if ("Max-Age".equalsIgnoreCase(attr))
854                    {                    {
855                      int delta = Integer.parseInt (val);                      int delta = Integer.parseInt(val);
856                      Calendar cal = Calendar.getInstance ();                      Calendar cal = Calendar.getInstance();
857                      cal.setTimeInMillis (System.currentTimeMillis ());                      cal.setTimeInMillis(System.currentTimeMillis());
858                      cal.add (Calendar.SECOND, delta);                      cal.add(Calendar.SECOND, delta);
859                      expires = cal.getTime ();                      expires = cal.getTime();
860                    }                    }
861                  else if ("Expires".equalsIgnoreCase (attr))                  else if ("Expires".equalsIgnoreCase(attr))
862                    {                    {
863                      DateFormat dateFormat = new HTTPDateFormat ();                      DateFormat dateFormat = new HTTPDateFormat();
864                      try                      try
865                        {                        {
866                          expires = dateFormat.parse (val);                          expires = dateFormat.parse(val);
867                        }                        }
868                      catch (ParseException e)                      catch (ParseException e)
869                        {                        {
870                          // if this isn't a valid date, it may be that                          // if this isn't a valid date, it may be that
871                          // the value was returned unquoted; in that case, we                          // the value was returned unquoted; in that case, we
872                          // want to continue buffering the value                          // want to continue buffering the value
873                          buf.append (c);                          buf.append(c);
874                          continue;                          continue;
875                        }                        }
876                    }                    }
877                  attr = null;                  attr = null;
878                  buf.setLength (0);                  buf.setLength(0);
879                  // case EOL                  // case EOL
880                  if (i == len || c == ',')                  if (i == len || c == ',')
881                    {                    {
882                      Cookie cookie = new Cookie (name, value, comment, domain,                      Cookie cookie = new Cookie(name, value, comment, domain,
883                                                  path, secure, expires);                                                 path, secure, expires);
884                      cookieManager.setCookie (cookie);                      cookieManager.setCookie(cookie);
885                    }                    }
886                  if (c == ',')                  if (c == ',')
887                    {                    {
# Line 889  public class Request Line 889  public class Request
889                      name = null;                      name = null;
890                      value = null;                      value = null;
891                      comment = null;                      comment = null;
892                      domain = connection.getHostName ();                      domain = connection.getHostName();
893                      path = this.path;                      path = this.path;
894                      if (lsi != -1)                      if (lsi != -1)
895                        {                        {
896                          path = path.substring (0, lsi);                          path = path.substring(0, lsi);
897                        }                        }
898                      secure = false;                      secure = false;
899                      expires = null;                      expires = null;
# Line 901  public class Request Line 901  public class Request
901                }                }
902              else              else
903                {                {
904                  buf.append (c);                  buf.append(c);
905                }                }
906            }            }
907          else          else
908            {            {
909              buf.append (c);              buf.append(c);
910            }            }
911        }        }
912    }    }
913    
914  }  }
915    

Legend:
Removed from v.1.13  
changed lines
  Added in v.1.14

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26