@Override public boolean reportIncorrect(Captcha captcha) { try (ScrapClient http = new ScrapClient()) { return http.get(apiUrl + "/captcha/" + captcha.getId() + "/report") == 200; } catch (Exception ex) { LOG.warn("exception ", ex); } return false; }
@Override public boolean solve(Captcha cap) { if (!(cap instanceof CaptchaImage)) { return false; } captchaCount.incrementAndGet(); CaptchaImage captcha = (CaptchaImage) cap; captcha.setLastSolver(this); captcha.setStatus(Captcha.Status.CREATED); String filename = null; String textMimeType = captcha.getMimes()[0]; String[] mimes = null; if (textMimeType != null) mimes = textMimeType.split("/"); else textMimeType = "application/octet-stream"; if (mimes != null && mimes.length == 2) { if (isValidImageExtension(mimes[1])) { filename = "image." + mimes[1]; } } else { filename = "image.png"; } Map<String, Object> data = getMapWithCredentials(); data.put( "captchafile", new ByteArrayBody(captcha.getImage(), ContentType.create(textMimeType), filename)); long started = System.currentTimeMillis(); captcha.setStatus(Captcha.Status.SUBMITTED); try (ScrapClient http = new ScrapClient()) { int httpStatus = 0; int retry = 0; while (true) { httpStatus = http.post(apiUrl + "captcha", data, ScrapClient.PostType.MULTIPART); if (!isRetryableStatus(httpStatus)) { break; } if (++retry > maxRetryOnOverload) { break; } try { Long sleep = 5000l * retry; LOG.debug("server is overloaded, sleeping {} ms", sleep); Thread.sleep(sleep); } catch (InterruptedException ex) { break; } } if (httpStatus >= 500) { captcha.setError(Captcha.Error.SERVICE_OVERLOADED); return false; } else if (httpStatus == 403) { captcha.setError(Captcha.Error.INVALID_CREDENTIALS); return false; } else if (httpStatus == 400) { captcha.setError(Captcha.Error.INVALID_CREDENTIALS); return false; } else if (httpStatus != 303) { captcha.setError(Captcha.Error.NETWORK_ERROR); return false; } String location = http.getResponseHeader("location"); if (location == null || !location.startsWith(apiUrl)) { LOG.warn("invalid location : {}", location); captcha.setError(Captcha.Error.NETWORK_ERROR); return false; } String captchaId = extractId(location); if (captchaId == null) { captcha.setError(Captcha.Error.NETWORK_ERROR); return false; } captcha.setId(captchaId); long timeLimit = System.currentTimeMillis() + timeoutMS; while (System.currentTimeMillis() < timeLimit) { int status = http.get(location + "?" + random.nextInt(Integer.MAX_VALUE)); if (status == 200) { Map<String, String> answer = parseAnswer(http.getContentAsString()); if (answer.get("text") != null && !answer.get("text").isEmpty()) { captcha.setResponse(answer.get("text")); captcha.setStatus(Captcha.Status.SOLVED); return true; } } try { Thread.sleep(POLLING_PAUSE_MS); } catch (InterruptedException ex) { break; } } captcha.setError(Captcha.Error.TIMEOUT); captcha.setStatus(Captcha.Status.ERROR); } catch (IOException ex) { LOG.error("io exception", ex); captcha.setError(EXCEPTION); } finally { captcha.setSolveDuration(System.currentTimeMillis() - started); } return false; }