示例#1
0
  public void switchTo(State state) {
    Log.info("Changing game state to [" + state + "] from [" + current + "]");
    game.updateLimiter.changedState();
    game.enterState(state.ordinal(), new FadeOutTransition(), new FadeInTransition());

    ScreenState last = (ScreenState) game.getState(current.ordinal());
    ScreenState next = (ScreenState) game.getState(state.ordinal());

    if (state == State.GAME) {
      ((GameState) next).start();
    } else if (current == State.GAME) {
      ((GameState) last).close();
    }
    current = state;
  }
示例#2
0
  /* ------------------------------------------------------------------------------- */
  private byte next(ByteBuffer buffer) {
    byte ch = buffer.get();

    if (_cr) {
      if (ch != HttpTokens.LINE_FEED) throw new BadMessage("Bad EOL");
      _cr = false;
      return ch;
    }

    if (ch >= 0 && ch < HttpTokens.SPACE) {
      if (ch == HttpTokens.CARRIAGE_RETURN) {
        if (buffer.hasRemaining()) {
          if (_maxHeaderBytes > 0 && _state.ordinal() < State.END.ordinal()) _headerBytes++;
          ch = buffer.get();
          if (ch != HttpTokens.LINE_FEED) throw new BadMessage("Bad EOL");
        } else {
          _cr = true;
          // Can return 0 here to indicate the need for more characters,
          // because a real 0 in the buffer would cause a BadMessage below
          return 0;
        }
      }
      // Only LF or TAB acceptable special characters
      else if (!(ch == HttpTokens.LINE_FEED || ch == HttpTokens.TAB))
        throw new BadMessage("Illegal character");
    }

    return ch;
  }
示例#3
0
  private byte next(ByteBuffer buffer) {
    byte ch = buffer.get();

    CharState s = __charState[0xff & ch];
    switch (s) {
      case ILLEGAL:
        throw new IllegalCharacterException(_state, ch, buffer);

      case LF:
        _cr = false;
        break;

      case CR:
        if (_cr) throw new BadMessageException("Bad EOL");

        _cr = true;
        if (buffer.hasRemaining()) {
          if (_maxHeaderBytes > 0 && _state.ordinal() < State.END.ordinal()) _headerBytes++;
          return next(buffer);
        }

        // Can return 0 here to indicate the need for more characters,
        // because a real 0 in the buffer would cause a BadMessage below
        return 0;

      case LEGAL:
        if (_cr) throw new BadMessageException("Bad EOL");
    }

    return ch;
  }
示例#4
0
  @Override
  protected void onPrepare() {
    width = cs.getWidth();
    height = cs.getHeight();
    state = State.RIGHT;
    ordinal = state.ordinal();

    controler = new Point(0, 0, null);
    point = new Point(controler.w, controler.h, null);
  }
示例#5
0
  private static int driver()

        // This is the driver of the FA.
        // If a valid token is found, assigns it to "t" and returns 1.
        // If an invalid token is found, assigns it to "t" and returns 0.
        // If end-of-stream is reached without finding any non-whitespace character, returns -1.

      {
    State nextSt; // the next state of the FA

    t = "";
    state = State.Start;

    if (Character.isWhitespace((char) a)) a = getChar(); // get the next non-whitespace character
    if (a == -1) // end-of-stream is reached
    return -1;

    while (a != -1) // do the body if "a" is not end-of-stream
    {
      c = (char) a;
      nextSt = nextState[state.ordinal()][a];
      if (nextSt == State.UNDEF) // The FA will halt.
      {
        if (isFinal(state)) return 1; // valid token extracted
        else // "c" is an unexpected character
        {
          t = t + c;
          a = getNextChar();
          return 0; // invalid token found
        }
      } else // The FA will go on.
      {
        state = nextSt;
        t = t + c;
        a = getNextChar();
      }
    }

    // end-of-stream is reached while a token is being extracted

    if (isFinal(state)) return 1; // valid token extracted
    else return 0; // invalid token found
  } // end driver
示例#6
0
  /**
   * Parse until next Event.
   *
   * @return True if an {@link RequestHandler} method was called and it returned true;
   */
  public boolean parseNext(ByteBuffer buffer) {
    if (DEBUG) LOG.debug("parseNext s={} {}", _state, BufferUtil.toDetailString(buffer));
    try {
      boolean handle = false;

      // Start a request/response
      if (_state == State.START) {
        _version = null;
        _method = null;
        _methodString = null;
        _endOfContent = EndOfContent.UNKNOWN_CONTENT;
        _header = null;
        handle = quickStart(buffer);
      }

      // Request/response line
      if (!handle
          && _state.ordinal() >= State.START.ordinal()
          && _state.ordinal() < State.HEADER.ordinal()) handle = parseLine(buffer);

      // parse headers
      if (!handle
          && _state.ordinal() >= State.HEADER.ordinal()
          && _state.ordinal() < State.CONTENT.ordinal()) handle = parseHeaders(buffer);

      // parse content
      if (!handle
          && _state.ordinal() >= State.CONTENT.ordinal()
          && _state.ordinal() < State.END.ordinal()) {
        // Handle HEAD response
        if (_responseStatus > 0 && _headResponse) {
          setState(State.END);
          handle = _handler.messageComplete();
        } else handle = parseContent(buffer);
      }

      // handle end states
      if (_state == State.END) {
        // eat white space
        while (buffer.remaining() > 0 && buffer.get(buffer.position()) <= HttpTokens.SPACE)
          buffer.get();
      } else if (_state == State.CLOSED) {
        if (BufferUtil.hasContent(buffer)) {
          // Just ignore data when closed
          _headerBytes += buffer.remaining();
          BufferUtil.clear(buffer);
          if (_headerBytes > _maxHeaderBytes) {
            // Don't want to waste time reading data of a closed request
            throw new IllegalStateException("too much data after closed");
          }
        }
      }

      // Handle EOF
      if (_eof && !buffer.hasRemaining()) {
        switch (_state) {
          case CLOSED:
            break;

          case START:
            _handler.earlyEOF();
            setState(State.CLOSED);
            break;

          case END:
            setState(State.CLOSED);
            break;

          case EOF_CONTENT:
            handle = _handler.messageComplete() || handle;
            setState(State.CLOSED);
            break;

          case CONTENT:
          case CHUNKED_CONTENT:
          case CHUNK_SIZE:
          case CHUNK_PARAMS:
          case CHUNK:
            _handler.earlyEOF();
            setState(State.CLOSED);
            break;

          default:
            if (DEBUG) LOG.debug("{} EOF in {}", this, _state);
            _handler.badMessage(400, null);
            setState(State.CLOSED);
            break;
        }
      }

      return handle;
    } catch (BadMessage e) {
      BufferUtil.clear(buffer);

      LOG.warn(
          "badMessage: "
              + e._code
              + (e._message != null ? " " + e._message : "")
              + " for "
              + _handler);
      if (DEBUG) LOG.debug(e);
      setState(State.CLOSED);
      _handler.badMessage(e._code, e._message);
      return false;
    } catch (Exception e) {
      BufferUtil.clear(buffer);

      LOG.warn("badMessage: " + e.toString() + " for " + _handler);
      if (DEBUG) LOG.debug(e);

      if (_state.ordinal() <= State.END.ordinal()) {
        setState(State.CLOSED);
        _handler.badMessage(400, null);
      } else {
        _handler.earlyEOF();
        setState(State.CLOSED);
      }

      return false;
    }
  }
 private synchronized void setState(State state, Throwable error) {
   this.state = state;
   handler.obtainMessage(MESSAGE_STATE_CHANGE, state.ordinal(), 0, error).sendToTarget();
 }
示例#8
0
  /*
   * Parse the message headers and return true if the handler has signaled for a return
   */
  protected boolean parseHeaders(ByteBuffer buffer) {
    boolean handle = false;

    // Process headers
    while (_state.ordinal() < State.CONTENT.ordinal() && buffer.hasRemaining() && !handle) {
      // process each character
      byte ch = next(buffer);
      if (ch == 0) break;

      if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) {
        LOG.warn("Header is too large >" + _maxHeaderBytes);
        throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
      }

      switch (_state) {
        case HEADER:
          switch (ch) {
            case HttpTokens.COLON:
            case HttpTokens.SPACE:
            case HttpTokens.TAB:
              {
                // header value without name - continuation?
                if (_valueString == null) {
                  _string.setLength(0);
                  _length = 0;
                } else {
                  setString(_valueString);
                  _string.append(' ');
                  _length++;
                  _valueString = null;
                }
                setState(State.HEADER_VALUE);
                break;
              }

            default:
              {
                // handler last header if any.  Delayed to here just in case there was a
                // continuation line (above)
                if (_headerString != null || _valueString != null) {
                  // Handle known headers
                  if (_header != null && handleKnownHeaders(buffer)) {
                    _headerString = _valueString = null;
                    _header = null;
                    _value = null;
                    _field = null;
                    return true;
                  }
                  handle =
                      _handler.parsedHeader(
                              _field != null
                                  ? _field
                                  : new HttpField(_header, _headerString, _valueString))
                          || handle;
                }
                _headerString = _valueString = null;
                _header = null;
                _value = null;
                _field = null;

                // now handle the ch
                if (ch == HttpTokens.LINE_FEED) {
                  _contentPosition = 0;

                  // End of headers!

                  // Was there a required host header?
                  if (!_host && _version != HttpVersion.HTTP_1_0 && _requestHandler != null) {
                    throw new BadMessage(HttpStatus.BAD_REQUEST_400, "No Host");
                  }

                  // is it a response that cannot have a body?
                  if (_responseHandler != null
                      && // response
                      (_responseStatus == 304
                          || // not-modified response
                          _responseStatus == 204
                          || // no-content response
                          _responseStatus < 200)) // 1xx response
                  _endOfContent = EndOfContent.NO_CONTENT; // ignore any other headers set

                  // else if we don't know framing
                  else if (_endOfContent == EndOfContent.UNKNOWN_CONTENT) {
                    if (_responseStatus == 0 // request
                        || _responseStatus == 304 // not-modified response
                        || _responseStatus == 204 // no-content response
                        || _responseStatus < 200) // 1xx response
                    _endOfContent = EndOfContent.NO_CONTENT;
                    else _endOfContent = EndOfContent.EOF_CONTENT;
                  }

                  // How is the message ended?
                  switch (_endOfContent) {
                    case EOF_CONTENT:
                      setState(State.EOF_CONTENT);
                      handle = _handler.headerComplete() || handle;
                      break;

                    case CHUNKED_CONTENT:
                      setState(State.CHUNKED_CONTENT);
                      handle = _handler.headerComplete() || handle;
                      break;

                    case NO_CONTENT:
                      handle = _handler.headerComplete() || handle;
                      setState(State.END);
                      handle = _handler.messageComplete() || handle;
                      break;

                    default:
                      setState(State.CONTENT);
                      handle = _handler.headerComplete() || handle;
                      break;
                  }
                } else if (ch <= HttpTokens.SPACE) throw new BadMessage();
                else {
                  if (buffer.hasRemaining()) {
                    // Try a look ahead for the known header name and value.
                    HttpField field =
                        _connectionFields == null
                            ? null
                            : _connectionFields.getBest(buffer, -1, buffer.remaining());
                    if (field == null) field = CACHE.getBest(buffer, -1, buffer.remaining());

                    if (field != null) {
                      final String n;
                      final String v;

                      if (_strict) {
                        // Have to get the fields exactly from the buffer to match case
                        String fn = field.getName();
                        String fv = field.getValue();
                        n =
                            BufferUtil.toString(
                                buffer,
                                buffer.position() - 1,
                                fn.length(),
                                StandardCharsets.US_ASCII);
                        if (fv == null) v = null;
                        else {
                          v =
                              BufferUtil.toString(
                                  buffer,
                                  buffer.position() + fn.length() + 1,
                                  fv.length(),
                                  StandardCharsets.ISO_8859_1);
                          field = new HttpField(field.getHeader(), n, v);
                        }
                      } else {
                        n = field.getName();
                        v = field.getValue();
                      }

                      _header = field.getHeader();
                      _headerString = n;

                      if (v == null) {
                        // Header only
                        setState(State.HEADER_VALUE);
                        _string.setLength(0);
                        _length = 0;
                        buffer.position(buffer.position() + n.length() + 1);
                        break;
                      } else {
                        // Header and value
                        int pos = buffer.position() + n.length() + v.length() + 1;
                        byte b = buffer.get(pos);

                        if (b == HttpTokens.CARRIAGE_RETURN || b == HttpTokens.LINE_FEED) {
                          _field = field;
                          _valueString = v;
                          setState(State.HEADER_IN_VALUE);

                          if (b == HttpTokens.CARRIAGE_RETURN) {
                            _cr = true;
                            buffer.position(pos + 1);
                          } else buffer.position(pos);
                          break;
                        } else {
                          setState(State.HEADER_IN_VALUE);
                          setString(v);
                          buffer.position(pos);
                          break;
                        }
                      }
                    }
                  }

                  // New header
                  setState(State.HEADER_IN_NAME);
                  _string.setLength(0);
                  _string.append((char) ch);
                  _length = 1;
                }
              }
          }
          break;

        case HEADER_IN_NAME:
          if (ch == HttpTokens.COLON || ch == HttpTokens.LINE_FEED) {
            if (_headerString == null) {
              _headerString = takeString();
              _header = HttpHeader.CACHE.get(_headerString);
            }
            _length = -1;

            setState(ch == HttpTokens.LINE_FEED ? State.HEADER : State.HEADER_VALUE);
            break;
          }

          if (ch >= HttpTokens.SPACE || ch == HttpTokens.TAB) {
            if (_header != null) {
              setString(_header.asString());
              _header = null;
              _headerString = null;
            }

            _string.append((char) ch);
            if (ch > HttpTokens.SPACE) _length = _string.length();
            break;
          }

          throw new BadMessage("Illegal character");

        case HEADER_VALUE:
          if (ch > HttpTokens.SPACE || ch < 0) {
            _string.append((char) (0xff & ch));
            _length = _string.length();
            setState(State.HEADER_IN_VALUE);
            break;
          }

          if (ch == HttpTokens.SPACE || ch == HttpTokens.TAB) break;

          if (ch == HttpTokens.LINE_FEED) {
            if (_length > 0) {
              _value = null;
              _valueString =
                  (_valueString == null) ? takeString() : (_valueString + " " + takeString());
            }
            setState(State.HEADER);
            break;
          }

          throw new BadMessage("Illegal character");

        case HEADER_IN_VALUE:
          if (ch >= HttpTokens.SPACE || ch < 0) {
            if (_valueString != null) {
              setString(_valueString);
              _valueString = null;
              _field = null;
            }
            _string.append((char) (0xff & ch));
            if (ch > HttpTokens.SPACE || ch < 0) _length = _string.length();
            break;
          }

          if (ch == HttpTokens.LINE_FEED) {
            if (_length > 0) {
              _value = null;
              _valueString = takeString();
              _length = -1;
            }
            setState(State.HEADER);
            break;
          }
          throw new BadMessage("Illegal character");

        default:
          throw new IllegalStateException(_state.toString());
      }
    }

    return handle;
  }
示例#9
0
  /* Parse a request or response line
   */
  private boolean parseLine(ByteBuffer buffer) {
    boolean handle = false;

    // Process headers
    while (_state.ordinal() < State.HEADER.ordinal() && buffer.hasRemaining() && !handle) {
      // process each character
      byte ch = next(buffer);
      if (ch == 0) break;

      if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) {
        if (_state == State.URI) {
          LOG.warn("URI is too large >" + _maxHeaderBytes);
          throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
        } else {
          if (_requestHandler != null) LOG.warn("request is too large >" + _maxHeaderBytes);
          else LOG.warn("response is too large >" + _maxHeaderBytes);
          throw new BadMessage(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413);
        }
      }

      switch (_state) {
        case METHOD:
          if (ch == HttpTokens.SPACE) {
            _length = _string.length();
            _methodString = takeString();
            HttpMethod method = HttpMethod.CACHE.get(_methodString);
            if (method != null && !_strict) _methodString = method.asString();
            setState(State.SPACE1);
          } else if (ch < HttpTokens.SPACE)
            throw new BadMessage(ch < 0 ? "Illegal character" : "No URI");
          else _string.append((char) ch);
          break;

        case RESPONSE_VERSION:
          if (ch == HttpTokens.SPACE) {
            _length = _string.length();
            String version = takeString();
            _version = HttpVersion.CACHE.get(version);
            if (_version == null)
              throw new BadMessage(HttpStatus.BAD_REQUEST_400, "Unknown Version");
            setState(State.SPACE1);
          } else if (ch < HttpTokens.SPACE)
            throw new BadMessage(ch < 0 ? "Illegal character" : "No Status");
          else _string.append((char) ch);
          break;

        case SPACE1:
          if (ch > HttpTokens.SPACE || ch < 0) {
            if (_responseHandler != null) {
              setState(State.STATUS);
              setResponseStatus(ch - '0');
            } else {
              _uri.clear();
              setState(State.URI);
              // quick scan for space or EoBuffer
              if (buffer.hasArray()) {
                byte[] array = buffer.array();
                int p = buffer.arrayOffset() + buffer.position();
                int l = buffer.arrayOffset() + buffer.limit();
                int i = p;
                while (i < l && array[i] > HttpTokens.SPACE) i++;

                int len = i - p;
                _headerBytes += len;

                if (_maxHeaderBytes > 0 && ++_headerBytes > _maxHeaderBytes) {
                  LOG.warn("URI is too large >" + _maxHeaderBytes);
                  throw new BadMessage(HttpStatus.REQUEST_URI_TOO_LONG_414);
                }
                if (_uri.remaining() <= len) {
                  ByteBuffer uri = ByteBuffer.allocate(_uri.capacity() + 2 * len);
                  _uri.flip();
                  uri.put(_uri);
                  _uri = uri;
                }
                _uri.put(array, p - 1, len + 1);
                buffer.position(i - buffer.arrayOffset());
              } else _uri.put(ch);
            }
          } else if (ch < HttpTokens.SPACE) {
            throw new BadMessage(
                HttpStatus.BAD_REQUEST_400, _requestHandler != null ? "No URI" : "No Status");
          }
          break;

        case STATUS:
          if (ch == HttpTokens.SPACE) {
            setState(State.SPACE2);
          } else if (ch >= '0' && ch <= '9') {
            _responseStatus = _responseStatus * 10 + (ch - '0');
          } else if (ch < HttpTokens.SPACE && ch >= 0) {
            handle = _responseHandler.startResponse(_version, _responseStatus, null) || handle;
            setState(State.HEADER);
          } else {
            throw new BadMessage();
          }
          break;

        case URI:
          if (ch == HttpTokens.SPACE) {
            setState(State.SPACE2);
          } else if (ch < HttpTokens.SPACE && ch >= 0) {
            // HTTP/0.9
            _uri.flip();
            handle = _requestHandler.startRequest(_method, _methodString, _uri, null) || handle;
            setState(State.END);
            BufferUtil.clear(buffer);
            handle = _handler.headerComplete() || handle;
            handle = _handler.messageComplete() || handle;
          } else {
            if (!_uri.hasRemaining()) {
              ByteBuffer uri = ByteBuffer.allocate(_uri.capacity() * 2);
              _uri.flip();
              uri.put(_uri);
              _uri = uri;
            }
            _uri.put(ch);
          }
          break;

        case SPACE2:
          if (ch > HttpTokens.SPACE) {
            _string.setLength(0);
            _string.append((char) ch);
            if (_responseHandler != null) {
              _length = 1;
              setState(State.REASON);
            } else {
              setState(State.REQUEST_VERSION);

              // try quick look ahead for HTTP Version
              HttpVersion version;
              if (buffer.position() > 0 && buffer.hasArray())
                version =
                    HttpVersion.lookAheadGet(
                        buffer.array(),
                        buffer.arrayOffset() + buffer.position() - 1,
                        buffer.arrayOffset() + buffer.limit());
              else version = HttpVersion.CACHE.getBest(buffer, 0, buffer.remaining());
              if (version != null) {
                int pos = buffer.position() + version.asString().length() - 1;
                if (pos < buffer.limit()) {
                  byte n = buffer.get(pos);
                  if (n == HttpTokens.CARRIAGE_RETURN) {
                    _cr = true;
                    _version = version;
                    _string.setLength(0);
                    buffer.position(pos + 1);
                  } else if (n == HttpTokens.LINE_FEED) {
                    _version = version;
                    _string.setLength(0);
                    buffer.position(pos);
                  }
                }
              }
            }
          } else if (ch == HttpTokens.LINE_FEED) {
            if (_responseHandler != null) {
              handle = _responseHandler.startResponse(_version, _responseStatus, null) || handle;
              setState(State.HEADER);
            } else {
              // HTTP/0.9
              _uri.flip();
              handle = _requestHandler.startRequest(_method, _methodString, _uri, null) || handle;
              setState(State.END);
              BufferUtil.clear(buffer);
              handle = _handler.headerComplete() || handle;
              handle = _handler.messageComplete() || handle;
            }
          } else if (ch < 0) throw new BadMessage();
          break;

        case REQUEST_VERSION:
          if (ch == HttpTokens.LINE_FEED) {
            if (_version == null) {
              _length = _string.length();
              _version = HttpVersion.CACHE.get(takeString());
            }
            if (_version == null)
              throw new BadMessage(HttpStatus.BAD_REQUEST_400, "Unknown Version");

            // Should we try to cache header fields?
            if (_connectionFields == null
                && _version.getVersion() >= HttpVersion.HTTP_1_1.getVersion()) {
              int header_cache = _handler.getHeaderCacheSize();
              if (header_cache > 0) _connectionFields = new ArrayTernaryTrie<>(header_cache);
            }

            setState(State.HEADER);
            _uri.flip();
            handle = _requestHandler.startRequest(_method, _methodString, _uri, _version) || handle;
            continue;
          } else if (ch >= HttpTokens.SPACE) _string.append((char) ch);
          else throw new BadMessage();

          break;

        case REASON:
          if (ch == HttpTokens.LINE_FEED) {
            String reason = takeString();

            setState(State.HEADER);
            handle = _responseHandler.startResponse(_version, _responseStatus, reason) || handle;
            continue;
          } else if (ch >= HttpTokens.SPACE) {
            _string.append((char) ch);
            if (ch != ' ' && ch != '\t') _length = _string.length();
          } else throw new BadMessage();
          break;

        default:
          throw new IllegalStateException(_state.toString());
      }
    }

    return handle;
  }
示例#10
0
 private State transition(Typechar c) {
   return table_f[current_state.ordinal()][c.ordinal()];
 }
示例#11
0
 public static PacketType findOldPacket(State state, Direction direction, int id) {
   return oldids.get(toShort((short) id, (short) direction.ordinal(), (short) state.ordinal()));
 }
 // Inclusive
 public boolean isBetween(final State min, final State max) {
   final int ord = ordinal();
   return ord >= min.ordinal() && ord <= max.ordinal();
 }
 public boolean isAtLeast(final State other) {
   return ordinal() >= other.ordinal();
 }
示例#14
0
 private boolean processCharacter(Event event) {
   int ordinal = transition[state.ordinal()][event.ordinal()];
   state = State.values()[ordinal];
   return state != State.INVALID;
 }
示例#15
0
 private boolean is_final_state(State s) {
   return s.ordinal() > State.SFINAL.ordinal();
 }
示例#16
0
  protected boolean parseContent(ByteBuffer buffer) {
    int remaining = buffer.remaining();
    if (remaining == 0 && _state == State.CONTENT) {
      long content = _contentLength - _contentPosition;
      if (content == 0) {
        setState(State.END);
        return _handler.messageComplete();
      }
    }

    // Handle _content
    byte ch;
    while (_state.ordinal() < State.END.ordinal() && remaining > 0) {
      switch (_state) {
        case EOF_CONTENT:
          _contentChunk = buffer.asReadOnlyBuffer();
          _contentPosition += remaining;
          buffer.position(buffer.position() + remaining);
          if (_handler.content(_contentChunk)) return true;
          break;

        case CONTENT:
          {
            long content = _contentLength - _contentPosition;
            if (content == 0) {
              setState(State.END);
              return _handler.messageComplete();
            } else {
              _contentChunk = buffer.asReadOnlyBuffer();

              // limit content by expected size
              if (remaining > content) {
                // We can cast remaining to an int as we know that it is
                // smaller than
                // or equal to length which is already an int.
                _contentChunk.limit(_contentChunk.position() + (int) content);
              }

              _contentPosition += _contentChunk.remaining();
              buffer.position(buffer.position() + _contentChunk.remaining());

              if (_handler.content(_contentChunk)) return true;

              if (_contentPosition == _contentLength) {
                setState(State.END);
                return _handler.messageComplete();
              }
            }
            break;
          }

        case CHUNKED_CONTENT:
          {
            ch = next(buffer);
            if (ch > HttpTokens.SPACE) {
              _chunkLength = TypeUtils.convertHexDigit(ch);
              _chunkPosition = 0;
              setState(State.CHUNK_SIZE);
            }

            break;
          }

        case CHUNK_SIZE:
          {
            ch = next(buffer);
            if (ch == 0) break;
            if (ch == HttpTokens.LINE_FEED) {
              if (_chunkLength == 0) setState(State.CHUNK_END);
              else setState(State.CHUNK);
            } else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
              setState(State.CHUNK_PARAMS);
            else _chunkLength = _chunkLength * 16 + TypeUtils.convertHexDigit(ch);
            break;
          }

        case CHUNK_PARAMS:
          {
            ch = next(buffer);
            if (ch == HttpTokens.LINE_FEED) {
              if (_chunkLength == 0) setState(State.CHUNK_END);
              else setState(State.CHUNK);
            }
            break;
          }

        case CHUNK:
          {
            int chunk = _chunkLength - _chunkPosition;
            if (chunk == 0) {
              setState(State.CHUNKED_CONTENT);
            } else {
              _contentChunk = buffer.asReadOnlyBuffer();

              if (remaining > chunk) _contentChunk.limit(_contentChunk.position() + chunk);
              chunk = _contentChunk.remaining();

              _contentPosition += chunk;
              _chunkPosition += chunk;
              buffer.position(buffer.position() + chunk);
              if (_handler.content(_contentChunk)) return true;
            }
            break;
          }

        case CHUNK_END:
          {
            // TODO handle chunk trailer
            ch = next(buffer);
            if (ch == 0) break;
            if (ch == HttpTokens.LINE_FEED) {
              setState(State.END);
              return _handler.messageComplete();
            }
            throw new IllegalCharacterException(_state, ch, buffer);
          }

        case CLOSED:
          {
            BufferUtils.clear(buffer);
            return false;
          }

        default:
          break;
      }

      remaining = buffer.remaining();
    }
    return false;
  }
示例#17
0
  /**
   * Parse until next Event.
   *
   * @param buffer the buffer to parse
   * @return True if an {@link RequestHandler} method was called and it returned true;
   */
  public boolean parseNext(ByteBuffer buffer) {
    if (DEBUG) log.debug("parseNext s={} {}", _state, BufferUtils.toDetailString(buffer));
    try {
      // Start a request/response
      if (_state == State.START) {
        _version = null;
        _method = null;
        _methodString = null;
        _endOfContent = EndOfContent.UNKNOWN_CONTENT;
        _header = null;
        if (quickStart(buffer)) return true;
      }

      // Request/response line
      if (_state.ordinal() >= State.START.ordinal() && _state.ordinal() < State.HEADER.ordinal()) {
        if (parseLine(buffer)) return true;
      }

      // parse headers
      if (_state.ordinal() >= State.HEADER.ordinal()
          && _state.ordinal() < State.CONTENT.ordinal()) {
        if (parseHeaders(buffer)) return true;
      }

      // parse content
      if (_state.ordinal() >= State.CONTENT.ordinal() && _state.ordinal() < State.END.ordinal()) {
        // Handle HEAD response
        if (_responseStatus > 0 && _headResponse) {
          setState(State.END);
          return _handler.messageComplete();
        } else {
          if (parseContent(buffer)) return true;
        }
      }

      // handle end states
      if (_state == State.END) {
        // eat white space
        while (buffer.remaining() > 0 && buffer.get(buffer.position()) <= HttpTokens.SPACE)
          buffer.get();
      } else if (_state == State.CLOSE) {
        // Seeking EOF
        if (BufferUtils.hasContent(buffer)) {
          // Just ignore data when closed
          _headerBytes += buffer.remaining();
          BufferUtils.clear(buffer);
          if (_maxHeaderBytes > 0 && _headerBytes > _maxHeaderBytes) {
            // Don't want to waste time reading data of a closed
            // request
            throw new IllegalStateException("too much data seeking EOF");
          }
        }
      } else if (_state == State.CLOSED) {
        BufferUtils.clear(buffer);
      }

      // Handle EOF
      if (_eof && !buffer.hasRemaining()) {
        switch (_state) {
          case CLOSED:
            break;

          case START:
            setState(State.CLOSED);
            _handler.earlyEOF();
            break;

          case END:
          case CLOSE:
            setState(State.CLOSED);
            break;

          case EOF_CONTENT:
            setState(State.CLOSED);
            return _handler.messageComplete();

          case CONTENT:
          case CHUNKED_CONTENT:
          case CHUNK_SIZE:
          case CHUNK_PARAMS:
          case CHUNK:
            setState(State.CLOSED);
            _handler.earlyEOF();
            break;

          default:
            if (DEBUG) log.debug("{} EOF in {}", this, _state);
            setState(State.CLOSED);
            _handler.badMessage(400, null);
            break;
        }
      }
    } catch (BadMessageException e) {
      BufferUtils.clear(buffer);

      Throwable cause = e.getCause();
      boolean stack =
          log.isDebugEnable()
              || (!(cause instanceof NumberFormatException)
                  && (cause instanceof RuntimeException || cause instanceof Error));

      if (stack)
        log.warn(
            "bad HTTP parsed: "
                + e._code
                + (e.getReason() != null ? " " + e.getReason() : "")
                + " for "
                + _handler,
            e);
      else
        log.warn(
            "bad HTTP parsed: "
                + e._code
                + (e.getReason() != null ? " " + e.getReason() : "")
                + " for "
                + _handler);
      setState(State.CLOSE);
      _handler.badMessage(e.getCode(), e.getReason());
    } catch (NumberFormatException | IllegalStateException e) {
      BufferUtils.clear(buffer);
      log.warn("parse exception: {} in {} for {}", e.toString(), _state, _handler);
      if (DEBUG) log.debug("parse exception", e);

      switch (_state) {
        case CLOSED:
          break;
        case CLOSE:
          _handler.earlyEOF();
          break;
        default:
          setState(State.CLOSE);
          _handler.badMessage(400, null);
      }
    } catch (Exception | Error e) {
      BufferUtils.clear(buffer);

      log.warn("parse exception: " + e.toString() + " for " + _handler, e);

      switch (_state) {
        case CLOSED:
          break;
        case CLOSE:
          _handler.earlyEOF();
          break;
        default:
          setState(State.CLOSE);
          _handler.badMessage(400, null);
      }
    }
    return false;
  }
 public boolean isAtMost(final State other) {
   return ordinal() <= other.ordinal();
 }
示例#19
0
  protected boolean parseContent(ByteBuffer buffer) {
    // Handle _content
    byte ch;
    while (_state.ordinal() < State.END.ordinal() && buffer.hasRemaining()) {
      switch (_state) {
        case EOF_CONTENT:
          _contentChunk = buffer.asReadOnlyBuffer();
          _contentPosition += _contentChunk.remaining();
          buffer.position(buffer.position() + _contentChunk.remaining());
          if (_handler.content(_contentChunk)) return true;
          break;

        case CONTENT:
          {
            long remaining = _contentLength - _contentPosition;
            if (remaining == 0) {
              setState(State.END);
              if (_handler.messageComplete()) return true;
            } else {
              _contentChunk = buffer.asReadOnlyBuffer();

              // limit content by expected size
              if (_contentChunk.remaining() > remaining) {
                // We can cast remaining to an int as we know that it is smaller than
                // or equal to length which is already an int.
                _contentChunk.limit(_contentChunk.position() + (int) remaining);
              }

              _contentPosition += _contentChunk.remaining();
              buffer.position(buffer.position() + _contentChunk.remaining());

              boolean handle = _handler.content(_contentChunk);
              if (_contentPosition == _contentLength) {
                setState(State.END);
                if (_handler.messageComplete()) return true;
              }
              if (handle) return true;
            }
            break;
          }

        case CHUNKED_CONTENT:
          {
            ch = next(buffer);
            if (ch > HttpTokens.SPACE) {
              _chunkLength = TypeUtil.convertHexDigit(ch);
              _chunkPosition = 0;
              setState(State.CHUNK_SIZE);
            }

            break;
          }

        case CHUNK_SIZE:
          {
            ch = next(buffer);
            if (ch == 0) break;
            if (ch == HttpTokens.LINE_FEED) {
              if (_chunkLength == 0) {
                setState(State.END);
                if (_handler.messageComplete()) return true;
              } else setState(State.CHUNK);
            } else if (ch <= HttpTokens.SPACE || ch == HttpTokens.SEMI_COLON)
              setState(State.CHUNK_PARAMS);
            else _chunkLength = _chunkLength * 16 + TypeUtil.convertHexDigit(ch);
            break;
          }

        case CHUNK_PARAMS:
          {
            ch = next(buffer);
            if (ch == HttpTokens.LINE_FEED) {
              if (_chunkLength == 0) {
                setState(State.END);
                if (_handler.messageComplete()) return true;
              } else setState(State.CHUNK);
            }
            break;
          }

        case CHUNK:
          {
            int remaining = _chunkLength - _chunkPosition;
            if (remaining == 0) {
              setState(State.CHUNKED_CONTENT);
            } else {
              _contentChunk = buffer.asReadOnlyBuffer();

              if (_contentChunk.remaining() > remaining)
                _contentChunk.limit(_contentChunk.position() + remaining);
              remaining = _contentChunk.remaining();

              _contentPosition += remaining;
              _chunkPosition += remaining;
              buffer.position(buffer.position() + remaining);
              if (_handler.content(_contentChunk)) return true;
            }
            break;
          }

        case CLOSED:
          {
            BufferUtil.clear(buffer);
            return false;
          }

        default:
          break;
      }
    }
    return false;
  }
示例#20
0
 /* ------------------------------------------------------------ */
 public boolean isCommitted() {
   return _state.ordinal() >= State.COMMITTED.ordinal();
 }
示例#21
0
 /* ------------------------------------------------------------------------------- */
 public boolean inContentState() {
   return _state.ordinal() >= State.CONTENT.ordinal() && _state.ordinal() < State.END.ordinal();
 }
  /**
   * Closes this channel and broadcasts the highest value payment transaction on the network.
   *
   * <p>This will set the state to {@link State#CLOSED} if the transaction is successfully broadcast
   * on the network. If we fail to broadcast for some reason, the state is set to {@link
   * State#ERROR}.
   *
   * <p>If the current state is before {@link State#READY} (ie we have not finished initializing the
   * channel), we simply set the state to {@link State#CLOSED} and let the client handle getting its
   * refund transaction confirmed.
   *
   * @return a future which completes when the provided multisig contract successfully broadcasts,
   *     or throws if the broadcast fails for some reason. Note that if the network simply rejects
   *     the transaction, this future will never complete, a timeout should be used.
   * @throws InsufficientMoneyException If the payment tx would have cost more in fees to spend than
   *     it is worth.
   */
  public synchronized ListenableFuture<Transaction> close() throws InsufficientMoneyException {
    if (storedServerChannel != null) {
      StoredServerChannel temp = storedServerChannel;
      storedServerChannel = null;
      StoredPaymentChannelServerStates channels =
          (StoredPaymentChannelServerStates)
              wallet.getExtensions().get(StoredPaymentChannelServerStates.EXTENSION_ID);
      channels.closeChannel(
          temp); // May call this method again for us (if it wasn't the original caller)
      if (state.compareTo(State.CLOSING) >= 0) return closedFuture;
    }

    if (state.ordinal() < State.READY.ordinal()) {
      log.error("Attempt to settle channel in state " + state);
      state = State.CLOSED;
      closedFuture.set(null);
      return closedFuture;
    }
    if (state != State.READY) {
      // TODO: What is this codepath for?
      log.warn("Failed attempt to settle a channel in state " + state);
      return closedFuture;
    }
    Transaction tx = null;
    try {
      Wallet.SendRequest req = makeUnsignedChannelContract(bestValueToMe);
      tx = req.tx;
      // Provide a throwaway signature so that completeTx won't complain out about unsigned inputs
      // it doesn't
      // know how to sign. Note that this signature does actually have to be valid, so we can't use
      // a dummy
      // signature to save time, because otherwise completeTx will try to re-sign it to make it
      // valid and then
      // die. We could probably add features to the SendRequest API to make this a bit more
      // efficient.
      signMultisigInput(tx, Transaction.SigHash.NONE, true);
      // Let wallet handle adding additional inputs/fee as necessary.
      req.shuffleOutputs = false;
      req.missingSigsMode = Wallet.MissingSigsMode.USE_DUMMY_SIG;
      wallet.completeTx(req); // TODO: Fix things so shuffling is usable.
      feePaidForPayment = req.tx.getFee();
      log.info("Calculated fee is {}", feePaidForPayment);
      if (feePaidForPayment.compareTo(bestValueToMe) > 0) {
        final String msg =
            String.format(
                Locale.US,
                "Had to pay more in fees (%s) than the channel was worth (%s)",
                feePaidForPayment,
                bestValueToMe);
        throw new InsufficientMoneyException(feePaidForPayment.subtract(bestValueToMe), msg);
      }
      // Now really sign the multisig input.
      signMultisigInput(tx, Transaction.SigHash.ALL, false);
      // Some checks that shouldn't be necessary but it can't hurt to check.
      tx.verify(); // Sanity check syntax.
      for (TransactionInput input : tx.getInputs())
        input.verify(); // Run scripts and ensure it is valid.
    } catch (InsufficientMoneyException e) {
      throw e; // Don't fall through.
    } catch (Exception e) {
      log.error(
          "Could not verify self-built tx\nMULTISIG {}\nCLOSE {}",
          multisigContract,
          tx != null ? tx : "");
      throw new RuntimeException(e); // Should never happen.
    }
    state = State.CLOSING;
    log.info("Closing channel, broadcasting tx {}", tx);
    // The act of broadcasting the transaction will add it to the wallet.
    ListenableFuture<Transaction> future = broadcaster.broadcastTransaction(tx).future();
    Futures.addCallback(
        future,
        new FutureCallback<Transaction>() {
          @Override
          public void onSuccess(Transaction transaction) {
            log.info("TX {} propagated, channel successfully closed.", transaction.getHash());
            state = State.CLOSED;
            closedFuture.set(transaction);
          }

          @Override
          public void onFailure(Throwable throwable) {
            log.error("Failed to settle channel, could not broadcast", throwable);
            state = State.ERROR;
            closedFuture.setException(throwable);
          }
        });
    return closedFuture;
  }
示例#23
0
 /* ------------------------------------------------------------------------------- */
 public boolean inHeaderState() {
   return _state.ordinal() < State.CONTENT.ordinal();
 }