aboutsummaryrefslogtreecommitdiff
path: root/libjava/gnu/gcj/protocol/http/Connection.java
blob: ba5903d0c12bf8e36c317741e168b6586ba5d6fd (plain)
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
// Connection.java - Implementation of HttpURLConnection for http protocol.

/* Copyright (C) 1999  Free Software Foundation

   This file is part of libgcj.

This software is copyrighted work licensed under the terms of the
Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
details.  */

package gnu.gcj.protocol.http;

import java.net.*;
import java.io.*;
import java.util.Vector;
import java.util.Hashtable;
import java.util.Enumeration;

/**
 * @author Warren Levy <warrenl@cygnus.com>
 * @date March 29, 1999.
 */

/**
 * Written using on-line Java Platform 1.2 API Specification, as well
 * as "The Java Class Libraries", 2nd edition (Addison-Wesley, 1998).
 * Status:  Minimal subset of functionality.  Proxies and Redirects
 *	not yet handled.  FileNameMap handling needs to be considered.
 *	useCaches, ifModifiedSince, and allowUserInteraction need
 *	consideration as well as doInput and doOutput.
 */

class Connection extends HttpURLConnection
{
  protected Socket sock = null;
  private static Hashtable defRequestProperties = new Hashtable();
  private Hashtable requestProperties;
  private Hashtable hdrHash = new Hashtable();
  private Vector hdrVec = new Vector();
  private boolean gotHeaders = false;
  private BufferedInputStream bufferedIn;

  public Connection(URL url)
  {
    super(url);
    requestProperties = (Hashtable) defRequestProperties.clone();
  }

  // Override method in URLConnection.
  public static void setDefaultRequestProperty(String key, String value)
  {
    defRequestProperties.put(key, value);
  }

  // Override method in URLConnection.
  public static String getDefaultRequestProperty(String key)
  {
    return (String) defRequestProperties.get(key);
  }

  // Override method in URLConnection.
  public void setRequestProperty(String key, String value)
  {
    if (connected)
      throw new IllegalAccessError("Connection already established.");

    requestProperties.put(key, value);
  }

  // Override method in URLConnection.
  public String getRequestProperty(String key)
  {
    if (connected)
      throw new IllegalAccessError("Connection already established.");

    return (String) requestProperties.get(key);
  }

  // Implementation of abstract method.
  public void connect() throws IOException
  {
    // Call is ignored if already connected.
    if (connected)
      return;

    // Get address and port number.
    int port;
    InetAddress destAddr = InetAddress.getByName(url.getHost());
    if ((port = url.getPort()) == -1)
      port = 80;

    // Open socket and output stream.
    sock = new Socket(destAddr, port);
    PrintWriter out = new PrintWriter(sock.getOutputStream());

    // Send request including any request properties that were set.
    out.print(getRequestMethod() + " " + url.getFile() + " HTTP/1.1\n");
    out.print("Host: " + url.getHost() + ":" + port + "\n");
    Enumeration reqKeys = requestProperties.keys();
    Enumeration reqVals = requestProperties.elements();
    while (reqKeys.hasMoreElements())
      out.print(reqKeys.nextElement() + ": " + reqVals.nextElement() + "\n");
    out.print("\n");
    out.flush();
    connected = true;
  }

  // Implementation of abstract method.
  public void disconnect()
  {
    if (sock != null)
      {
	try
	  {
	    sock.close();
	  }
	catch (IOException ex)
	  {
	    ; // Ignore errors in closing socket.
	  }
	sock = null;
      }
    connected = false;
  }

  // TODO: public boolean usingProxy()
  public boolean usingProxy()
  {
    throw new InternalError("HttpURLConnection.usingProxy not implemented");
  }

  // Override default method in URLConnection.
  public InputStream getInputStream() throws IOException
  {
    if (!connected)
      connect();

    if (! doInput)
      throw new ProtocolException("Can't open InputStream if doInput is false");
    if (bufferedIn == null)
      bufferedIn = new BufferedInputStream(sock.getInputStream());
    return bufferedIn;
  }

  // Override default method in URLConnection.
  public OutputStream getOutputStream() throws IOException
  {
    if (!connected)
      connect();

    if (! doOutput)
      throw new
	ProtocolException("Can't open OutputStream if doOutput is false");
    return sock.getOutputStream();
  }

  // Override default method in URLConnection.
  public String getHeaderField(String name)
  {
    try
      {
	getHttpHeaders();
      }
    catch (IOException x)
      {
	return null;
      }
    return (String) hdrHash.get(name.toLowerCase());
  }

  // Override default method in URLConnection.
  public String getHeaderField(int n)
  {
    try
      {
	getHttpHeaders();
      }
    catch (IOException x)
      {
	return null;
      }
    if (n < hdrVec.size())
      return getField((String) hdrVec.elementAt(n));

    return null;
  }

  // Override default method in URLConnection.
  public String getHeaderFieldKey(int n)
  {
    try
      {
	getHttpHeaders();
      }
    catch (IOException x)
      {
	return null;
      }
    if (n < hdrVec.size())
      return getKey((String) hdrVec.elementAt(n));

    return null;
  }

  private String getKey(String str)
  {
    if (str == null)
      return null;
    int index = str.indexOf(':');
    if (index >= 0)
      return str.substring(0, index);
    else
      return null;
  }

  private String getField(String str)
  {
    if (str == null)
      return null;
    int index = str.indexOf(':');
    if (index >= 0)
      return str.substring(index + 1).trim();
    else
      return str;
  }

  private void getHttpHeaders() throws IOException
  {
    if (gotHeaders)
      return;
    gotHeaders = true;

    connect();

    // Originally tried using a BufferedReader here to take advantage of
    // the readLine method and avoid the following, but the buffer read
    // past the end of the headers so the first part of the content was lost.
    // It is probably more robust than it needs to be, e.g. the byte[]
    // is unlikely to overflow and a '\r' should always be followed by a '\n',
    // but it is better to be safe just in case.
    if (bufferedIn == null)
      bufferedIn = new BufferedInputStream(sock.getInputStream());

    int buflen = 100;
    byte[] buf = new byte[buflen];
    String line = "";
    boolean gotnl = false;
    byte[] ch = new byte[1];
    ch[0] = (byte) '\n';
    while (true)
      {
	// Check for leftover byte from non-'\n' after a '\r'.
	if (ch[0] != '\n')
	  line = line + '\r' + new String(ch, 0, 1);

	int i;
	for (i = 0; i < buflen; i++)
	  {
	    bufferedIn.read(buf, i, 1);
	    if (buf[i] == '\r')
	      {
	        bufferedIn.read(ch, 0, 1);
		if (ch[0] == '\n')
		  gotnl = true;
		break;
	      }
	  }
	line = line + new String(buf, 0, i);

	// A '\r' '\n' combo indicates the end of the header entry.
	// If it wasn't found, cycle back through the loop and append
	// to 'line' until one is found.
	if (gotnl)
	  {
	    // A zero length entry signals the end of the headers.
	    if (line.length() == 0)
	      break;

	    // Store the header and reinitialize for next cycle.
	    hdrVec.addElement(line);
	    String key = getKey(line);
	    if (key != null)
	      hdrHash.put(key.toLowerCase(), getField(line));
	    line = "";
	    ch[0] = (byte) '\n';
	    gotnl = false;
	  }
      }
  }
}