Пример #1
0
 private void recycleSocket(final AsyncSocket socket, AsyncHttpRequest request) {
   if (socket == null) return;
   URI uri = request.getUri();
   int port = getSchemePort(uri);
   String lookup = computeLookup(uri, port, request);
   // nothing here will block...
   synchronized (this) {
     HashSet<AsyncSocket> sockets = mSockets.get(lookup);
     if (sockets == null) {
       sockets = new HashSet<AsyncSocket>();
       mSockets.put(lookup, sockets);
     }
     final HashSet<AsyncSocket> ss = sockets;
     sockets.add(socket);
     socket.setClosedCallback(
         new CompletedCallback() {
           @Override
           public void onCompleted(Exception ex) {
             synchronized (AsyncSocketMiddleware.this) {
               ss.remove(socket);
             }
             socket.setClosedCallback(null);
           }
         });
   }
 }
Пример #2
0
 private void idleSocket(final AsyncSocket socket) {
   // must listen for socket close, otherwise log will get spammed.
   socket.setEndCallback(
       new CompletedCallback() {
         @Override
         public void onCompleted(Exception ex) {
           socket.close();
         }
       });
   socket.setWriteableCallback(null);
   // should not get any data after this point...
   // if so, eat it and disconnect.
   socket.setDataCallback(
       new NullDataCallback() {
         @Override
         public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
           super.onDataAvailable(emitter, bb);
           bb.recycle();
           socket.close();
         }
       });
 }
  void setSocket(AsyncSocket exchange) {
    mSocket = exchange;

    if (mSocket == null) return;

    mWriter = mRequest.getBody();
    if (mWriter != null) {
      mRequest.getHeaders().setContentType(mWriter.getContentType());
      if (mWriter.length() != -1) {
        mRequest.getHeaders().setContentLength(mWriter.length());
        mSink = mSocket;
      } else {
        mRequest.getHeaders().getHeaders().set("Transfer-Encoding", "Chunked");
        mSink = new ChunkedOutputFilter(mSocket);
      }
    } else {
      mSink = mSocket;
    }

    String rs = mRequest.getRequestString();
    com.koushikdutta.async.Util.writeAll(
        exchange,
        rs.getBytes(),
        new CompletedCallback() {
          @Override
          public void onCompleted(Exception ex) {
            if (mWriter != null) mWriter.write(mRequest, AsyncHttpResponseImpl.this);
          }
        });

    LineEmitter liner = new LineEmitter();
    exchange.setDataCallback(liner);
    liner.setLineCallback(mHeaderCallback);

    mSocket.setEndCallback(mReporter);
    mSocket.setClosedCallback(
        new CompletedCallback() {
          @Override
          public void onCompleted(Exception ex) {
            // TODO: do we care? throw if socket is still writing or something?
          }
        });
  }
Пример #4
0
  @Override
  public Cancellable getSocket(final AsyncHttpClientMiddleware.GetSocketData data) {
    final URI uri = data.request.getUri();
    final int port = getSchemePort(data.request.getUri());
    if (port == -1) {
      return null;
    }

    ConnectionInfo info = getConnectionInfo(uri.getScheme(), uri.getHost(), port);
    if (info.openCount >= maxConnectionCount) {
      // wait for a connection queue to free up
      SimpleCancellable queueCancel = new SimpleCancellable();
      info.queue.add(data);
      return queueCancel;
    }

    info.openCount++;

    final String lookup = computeLookup(uri, port, data.request);

    data.state.putBoolean(getClass().getCanonicalName() + ".owned", true);

    synchronized (this) {
      final HashSet<AsyncSocket> sockets = mSockets.get(lookup);
      if (sockets != null) {
        for (final AsyncSocket socket : sockets) {
          if (socket.isOpen()) {
            sockets.remove(socket);
            socket.setClosedCallback(null);

            mClient
                .getServer()
                .post(
                    new Runnable() {
                      @Override
                      public void run() {
                        data.request.logd("Reusing keep-alive socket");
                        data.connectCallback.onConnectCompleted(null, socket);
                      }
                    });

            // replace above code with immediate callback?
            //                        data.request.logd("Reusing keep-alive socket");
            //                        data.connectCallback.onConnectCompleted(null, socket);

            // just a noop/dummy, as this can't actually be cancelled.
            return new SimpleCancellable();
          }
        }
      }
    }

    if (!connectAllAddresses || proxyHost != null || data.request.getProxyHost() != null) {
      // just default to connecting to a single address
      data.request.logd("Connecting socket");
      String unresolvedHost;
      int unresolvedPort;
      if (data.request.getProxyHost() != null) {
        unresolvedHost = data.request.getProxyHost();
        unresolvedPort = data.request.getProxyPort();
        // set the host and port explicitly for proxied connections
        data.request
            .getHeaders()
            .getHeaders()
            .setStatusLine(data.request.getProxyRequestLine().toString());
      } else if (proxyHost != null) {
        unresolvedHost = proxyHost;
        unresolvedPort = proxyPort;
        // set the host and port explicitly for proxied connections
        data.request
            .getHeaders()
            .getHeaders()
            .setStatusLine(data.request.getProxyRequestLine().toString());
      } else {
        unresolvedHost = uri.getHost();
        unresolvedPort = port;
      }
      return mClient
          .getServer()
          .connectSocket(
              unresolvedHost, unresolvedPort, wrapCallback(data.connectCallback, uri, port));
    }

    // try to connect to everything...
    data.request.logv("Resolving domain and connecting to all available addresses");
    return mClient
        .getServer()
        .getAllByName(uri.getHost())
        .then(
            new TransformFuture<AsyncSocket, InetAddress[]>() {
              Exception lastException;

              @Override
              protected void error(Exception e) {
                super.error(e);
                data.connectCallback.onConnectCompleted(e, null);
              }

              @Override
              protected void transform(final InetAddress[] result) throws Exception {
                Continuation keepTrying =
                    new Continuation(
                        new CompletedCallback() {
                          @Override
                          public void onCompleted(Exception ex) {
                            // if it completed, that means that the connection failed
                            if (lastException == null)
                              lastException =
                                  new ConnectionFailedException(
                                      "Unable to connect to remote address");
                            setComplete(lastException);
                          }
                        });

                for (final InetAddress address : result) {
                  keepTrying.add(
                      new ContinuationCallback() {
                        @Override
                        public void onContinue(
                            Continuation continuation, final CompletedCallback next)
                            throws Exception {
                          mClient
                              .getServer()
                              .connectSocket(
                                  new InetSocketAddress(address, port),
                                  wrapCallback(
                                      new ConnectCallback() {
                                        @Override
                                        public void onConnectCompleted(
                                            Exception ex, AsyncSocket socket) {
                                          if (isDone()) {
                                            lastException =
                                                new Exception("internal error during connect");
                                            next.onCompleted(null);
                                            return;
                                          }

                                          // try the next address
                                          if (ex != null) {
                                            lastException = ex;
                                            next.onCompleted(null);
                                            return;
                                          }

                                          // if the socket is no longer needed, just hang onto it...
                                          if (isDone() || isCancelled()) {
                                            data.request.logd(
                                                "Recycling extra socket leftover from cancelled operation");
                                            idleSocket(socket);
                                            recycleSocket(socket, data.request);
                                            return;
                                          }

                                          if (setComplete(null, socket)) {
                                            data.connectCallback.onConnectCompleted(ex, socket);
                                          }
                                        }
                                      },
                                      uri,
                                      port));
                        }
                      });
                }

                keepTrying.start();
              }
            });
  }
 @Override
 public AsyncServer getServer() {
   return mSocket.getServer();
 }
Пример #6
0
        @Override
        public void onAccepted(final AsyncSocket socket) {
          AsyncHttpServerRequestImpl req =
              new AsyncHttpServerRequestImpl() {
                Pair match;
                String fullPath;
                String path;
                boolean responseComplete;
                boolean requestComplete;
                AsyncHttpServerResponseImpl res;
                boolean hasContinued;

                @Override
                protected AsyncHttpRequestBody onUnknownBody(RawHeaders headers) {
                  return AsyncHttpServer.this.onUnknownBody(headers);
                }

                @Override
                protected void onHeadersReceived() {
                  RawHeaders headers = getRawHeaders();

                  // should the negotiation of 100 continue be here, or in the request impl?
                  // probably here, so AsyncResponse can negotiate a 100 continue.
                  if (!hasContinued && "100-continue".equals(headers.get("Expect"))) {
                    pause();
                    //                        System.out.println("continuing...");
                    Util.writeAll(
                        mSocket,
                        "HTTP/1.1 100 Continue\r\n\r\n".getBytes(),
                        new CompletedCallback() {
                          @Override
                          public void onCompleted(Exception ex) {
                            resume();
                            if (ex != null) {
                              report(ex);
                              return;
                            }
                            hasContinued = true;
                            onHeadersReceived();
                          }
                        });
                    return;
                  }
                  //                    System.out.println(headers.toHeaderString());

                  String statusLine = headers.getStatusLine();
                  String[] parts = statusLine.split(" ");
                  fullPath = parts[1];
                  path = fullPath.split("\\?")[0];
                  method = parts[0];
                  synchronized (mActions) {
                    ArrayList<Pair> pairs = mActions.get(method);
                    if (pairs != null) {
                      for (Pair p : pairs) {
                        Matcher m = p.regex.matcher(path);
                        if (m.matches()) {
                          mMatcher = m;
                          match = p;
                          break;
                        }
                      }
                    }
                  }
                  res =
                      new AsyncHttpServerResponseImpl(socket, this) {
                        @Override
                        protected void onEnd() {
                          super.onEnd();
                          mSocket.setEndCallback(null);
                          responseComplete = true;
                          // reuse the socket for a subsequent request.
                          handleOnCompleted();
                        }
                      };

                  onRequest(this, res);

                  if (match == null) {
                    res.responseCode(404);
                    res.end();
                    return;
                  }

                  if (!getBody().readFullyOnRequest()) {
                    match.callback.onRequest(this, res);
                  } else if (requestComplete) {
                    match.callback.onRequest(this, res);
                  }
                }

                @Override
                public void onCompleted(Exception e) {
                  // if the protocol was switched off http, ignore this request/response.
                  if (res.getHeaders().getHeaders().getResponseCode() == 101) return;
                  requestComplete = true;
                  super.onCompleted(e);
                  // no http pipelining, gc trashing if the socket dies
                  // while the request is being sent and is paused or something
                  mSocket.setDataCallback(
                      new NullDataCallback() {
                        @Override
                        public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
                          super.onDataAvailable(emitter, bb);
                          mSocket.close();
                        }
                      });
                  handleOnCompleted();

                  if (getBody().readFullyOnRequest()) {
                    if (match != null) match.callback.onRequest(this, res);
                  }
                }

                private void handleOnCompleted() {
                  if (requestComplete && responseComplete) {
                    if (HttpUtil.isKeepAlive(getHeaders().getHeaders())) {
                      onAccepted(socket);
                    } else {
                      socket.close();
                    }
                  }
                }

                @Override
                public String getPath() {
                  return path;
                }

                @Override
                public Multimap getQuery() {
                  String[] parts = fullPath.split("\\?", 2);
                  if (parts.length < 2) return new Multimap();
                  return Multimap.parseQuery(parts[1]);
                }
              };
          req.setSocket(socket);
          socket.resume();
        }