/* * Copyright (C) 2010, Google Inc. * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available * under the terms of the Eclipse Distribution License v1.0 which * accompanies this distribution, is reproduced below, and is * available at http://www.eclipse.org/org/documents/edl-v10.php * * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted provided that the following * conditions are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided * with the distribution. * * - Neither the name of the Eclipse Foundation, Inc. nor the * names of its contributors may be used to endorse or promote * products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.eclipse.jgit.iplog; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.net.ConnectException; import java.net.CookieHandler; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.Proxy; import java.net.ProxySelector; import java.net.URISyntaxException; import java.net.URL; import java.net.URLEncoder; import java.text.MessageFormat; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.jgit.util.HttpSupport; /** A crude interface to query IPzilla. */ class IPZillaQuery { private static final String RE_EPL = "^.*(Eclipse Public License|EPL).*$"; private final URL base; private final String username; private final String password; private final ProxySelector proxySelector = ProxySelector.getDefault(); IPZillaQuery(URL base, String username, String password) { this.base = base; this.username = username; this.password = password; } Set getCQs(Collection projects) throws IOException { try { login(); Set cqs = new HashSet(); for (Project project : projects) cqs.addAll(queryOneProject(project)); return cqs; } finally { // Kill the IPzilla session and log us out from there. logout(); } } private Set queryOneProject(Project project) throws IOException { Map p = new LinkedHashMap(); p.put("bugidtype", "include"); p.put("chfieldto", "Now"); p.put("component", project.getID()); p.put("field-1-0-0", "component"); p.put("type-1-0-0", "anyexact"); p.put("value-1-0-0", project.getID()); p.put("ctype", "csv"); StringBuilder req = new StringBuilder(); for (Map.Entry e : p.entrySet()) { if (req.length() > 0) req.append('&'); req.append(URLEncoder.encode(e.getKey(), "UTF-8")); req.append('='); req.append(URLEncoder.encode(e.getValue(), "UTF-8")); } URL csv = new URL(new URL(base, "buglist.cgi").toString() + "?" + req); req = new StringBuilder(); for (String name : new String[] { "bug_severity", "bug_status", "resolution", "short_desc", "cf_license", "keywords" }) { if (req.length() > 0) req.append("%20"); req.append(name); } setCookie(csv, "COLUMNLIST", req.toString()); HttpURLConnection conn = open(csv); if (HttpSupport.response(conn) != HttpURLConnection.HTTP_OK) { throw new IOException(MessageFormat.format(IpLogText.get().queryFailed , csv, conn.getResponseCode() + " " + conn.getResponseMessage())); } BufferedReader br = reader(conn); try { Set cqs = new HashSet(); CSV in = new CSV(br); Map row; while ((row = in.next()) != null) { CQ cq = parseOneCQ(row); if (cq != null) cqs.add(cq); } return cqs; } finally { br.close(); } } private BufferedReader reader(HttpURLConnection conn) throws UnsupportedEncodingException, IOException { String encoding = conn.getContentEncoding(); InputStream in = conn.getInputStream(); if (encoding != null && !encoding.equals("")) return new BufferedReader(new InputStreamReader(in, encoding)); return new BufferedReader(new InputStreamReader(in)); } private void login() throws MalformedURLException, UnsupportedEncodingException, ConnectException, IOException { final URL login = new URL(base, "index.cgi"); StringBuilder req = new StringBuilder(); req.append("Bugzilla_login="); req.append(URLEncoder.encode(username, "UTF-8")); req.append('&'); req.append("Bugzilla_password="); req.append(URLEncoder.encode(password, "UTF-8")); byte[] reqbin = req.toString().getBytes("UTF-8"); HttpURLConnection c = open(login); c.setDoOutput(true); c.setFixedLengthStreamingMode(reqbin.length); c.setRequestProperty(HttpSupport.HDR_CONTENT_TYPE, "application/x-www-form-urlencoded"); OutputStream out = c.getOutputStream(); out.write(reqbin); out.close(); if (HttpSupport.response(c) != HttpURLConnection.HTTP_OK) { throw new IOException(MessageFormat.format(IpLogText.get().loginFailed , username, login, c.getResponseCode() + " " + c.getResponseMessage())); } String content = readFully(c); Matcher matcher = Pattern.compile("(.*)", Pattern.CASE_INSENSITIVE).matcher(content); if (!matcher.find()) { throw new IOException(MessageFormat.format(IpLogText.get().loginFailed , username, login, IpLogText.get().responseNotHTMLAsExpected)); } String title = matcher.group(1); if (!"IPZilla Main Page".equals(title)) { throw new IOException(MessageFormat.format(IpLogText.get().loginFailed , username, login , MessageFormat.format(IpLogText.get().pageTitleWas, title))); } } private String readFully(HttpURLConnection c) throws IOException { String enc = c.getContentEncoding(); Reader reader; if (enc != null) { reader = new InputStreamReader(c.getInputStream(), enc); } else { reader = new InputStreamReader(c.getInputStream(), "ISO-8859-1"); } try { StringBuilder b = new StringBuilder(); BufferedReader r = new BufferedReader(reader); String line; while ((line = r.readLine()) != null) { b.append(line).append('\n'); } return b.toString(); } finally { reader.close(); } } private void logout() throws MalformedURLException, ConnectException, IOException { HttpSupport.response(open(new URL(base, "relogin.cgi"))); } private HttpURLConnection open(URL url) throws ConnectException, IOException { Proxy proxy = HttpSupport.proxyFor(proxySelector, url); HttpURLConnection c = (HttpURLConnection) url.openConnection(proxy); c.setUseCaches(false); return c; } private void setCookie(URL url, String name, String value) throws IOException { Map> cols = new HashMap>(); cols.put("Set-Cookie", Collections.singletonList(name + "=" + value)); try { CookieHandler.getDefault().put(url.toURI(), cols); } catch (URISyntaxException e) { IOException err = new IOException(MessageFormat.format(IpLogText.get().invalidURIFormat, url)); err.initCause(e); throw err; } } private CQ parseOneCQ(Map row) { long id = Long.parseLong(row.get("bug_id")); String state = row.get("bug_severity"); String bug_status = row.get("bug_status"); String resolution = row.get("resolution"); String short_desc = row.get("short_desc"); String license = row.get("cf_license"); Set keywords = new TreeSet(); for (String w : row.get("keywords").split(", *")) keywords.add(w); // Skip any CQs that were not accepted. // if ("closed".equalsIgnoreCase(state) || "rejected".equalsIgnoreCase(state) || "withdrawn".equalsIgnoreCase(state)) return null; // Skip any CQs under the EPL without nonepl keyword // Skip any CQs with the EPL keyword // if (!keywords.contains("nonepl") && license.matches(RE_EPL)) return null; if (keywords.contains("epl")) return null; // Work around CQs that were closed in the wrong state. // if ("new".equalsIgnoreCase(state) || "under_review".equalsIgnoreCase(state) || state.startsWith("awaiting_")) { if ("RESOLVED".equalsIgnoreCase(bug_status) || "CLOSED".equalsIgnoreCase(bug_status)) { if ("FIXED".equalsIgnoreCase(resolution)) state = "approved"; else return null; } } StringBuilder use = new StringBuilder(); for (String n : new String[] { "unmodified", "modified", "source", "binary" }) { if (keywords.contains(n)) { if (use.length() > 0) use.append(' '); use.append(n); } } if (keywords.contains("sourceandbinary")) { if (use.length() > 0) use.append(' '); use.append("source & binary"); } CQ cq = new CQ(id); cq.setDescription(short_desc); cq.setLicense(license); cq.setState(state); if (use.length() > 0) cq.setUse(use.toString().trim()); return cq; } }