bd718e4623911fb25d683bd0288b130653112f2c
[aaf/authz.git] / auth / auth-core / src / main / java / org / onap / aaf / auth / rserv / Acceptor.java
1 /**
2  * ============LICENSE_START====================================================
3  * org.onap.aaf
4  * ===========================================================================
5  * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved.
6  * ===========================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END====================================================
19  *
20  */
21
22 package org.onap.aaf.auth.rserv;
23
24 import java.util.ArrayList;
25 import java.util.Iterator;
26 import java.util.List;
27
28 import org.onap.aaf.misc.env.Trans;
29
30 /**
31  * Find Acceptable Paths and place them where TypeCode can evaluate.
32  *
33  * If there are more than one, TypeCode will choose based on "q" value
34  * @author Jonathan
35  *
36  * @param <TRANS>
37  */
38 class Acceptor<TRANS extends Trans>  {
39     private List<Pair<String, Pair<HttpCode<TRANS,?>, List<Pair<String, Object>>>>> types;
40     List<Pair<String, Pair<HttpCode<TRANS,?>, List<Pair<String, Object>>>>> acceptable;
41
42     public Acceptor(List<Pair<String, Pair<HttpCode<TRANS,?>, List<Pair<String, Object>>>>> types) {
43         this.types = types;
44         acceptable = new ArrayList<>();
45     }
46
47     private boolean eval(HttpCode<TRANS,?> code, String str, List<String> props) {
48 //        int plus = str.indexOf('+');
49 //        if (plus<0) {
50         boolean ok = false;
51         boolean any = false;
52         for (Pair<String, Pair<HttpCode<TRANS,?>, List<Pair<String, Object>>>> type : types) {
53             ok = true;
54             if (type.x.equals(str)) {
55                 for (Iterator<String> iter = props.iterator();ok && iter.hasNext();) {
56                     ok = props(type,iter.next(),iter.next());
57                 }
58                 if (ok) {
59                     any = true;
60                     acceptable.add(type);
61                 }
62             }
63         }
64 //        } else { // Handle Accepts with "+" as in application/xaml+xml
65 //            int prev = str.indexOf('/')+1;
66 //            String first = str.substring(0,prev);
67 //            String nstr;
68 //            while (prev!=0) {
69 //                nstr = first + (plus<0?str.substring(prev):str.substring(prev,plus));
70 //
71 //                for (Pair<String, Pair<HttpCode<TRANS,?>, List<Pair<String, Object>>>> type : types) {
72 //                    if (type.x.equals(nstr)) {
73 //                        acceptable.add(type);
74 //                        return type;
75 //                    }
76 //                }
77 //                prev = plus+1;
78 //                plus=str.indexOf('+', prev);
79 //            };
80 //        }
81         return any;
82     }
83
84     /**
85      * Evaluate Properties
86      * @param type
87      * @param tag
88      * @param value
89      * @return
90      */
91     private boolean props(Pair<String, Pair<HttpCode<TRANS,?>, List<Pair<String, Object>>>> type, String tag, String value) {
92         boolean rv = false;
93         if (type.y!=null) {
94             for (Pair<String,Object> prop : type.y.y){
95                 if (tag.equals(prop.x)) {
96                     if (tag.equals("charset")) {
97                         return prop.x==null?false:prop.y.equals(value.toLowerCase()); // return True if Matched
98                     } else if (tag.equals("version")) {
99                         return prop.y.equals(new Version(value)); // Note: Version Class knows Minor Version encoding
100                     } else if (tag.equals(Content.Q)) { // replace Q value
101                         try {
102                             type.y.y.get(0).y=Float.parseFloat(value);
103                         } catch (NumberFormatException e) {
104                             rv=false; // need to do something to make Sonar happy. But nothing to do.
105                         }
106                         return true;
107                     } else {
108                         return value.equals(prop.y);
109                     }
110                 }
111             }
112         }
113         return rv;
114     }
115
116     /**
117      * parse
118      *
119      * Note: I'm processing by index to avoid lots of memory creation, which speeds things
120      * up for this time critical section of code.
121      * @param code
122      * @param cntnt
123      * @return
124      */
125     protected boolean parse(HttpCode<TRANS, ?> code, String cntnt) {
126         byte bytes[] = cntnt.getBytes();
127
128         int cis,cie=-1,cend;
129         int sis,sie,send;
130         String name;
131         ArrayList<String> props = new ArrayList<>();
132         do {
133             // Clear these in case more than one Semi
134             props.clear(); // on loop, do not want mixed properties
135             name=null;
136
137             cis = cie+1; // find comma start
138             while (cis<bytes.length && Character.isSpaceChar(bytes[cis]))++cis;
139             cie = cntnt.indexOf(',',cis); // find comma end
140             cend = cie<0?bytes.length:cie; // If no comma, set comma end to full length, else cie
141             while (cend>cis && Character.isSpaceChar(bytes[cend-1]))--cend;
142             // Start SEMIS
143             sie=cis-1;
144             do {
145                 sis = sie+1;  // semi start is one after previous end
146                 while (sis<bytes.length && Character.isSpaceChar(bytes[sis]))++sis;
147                 sie = cntnt.indexOf(';',sis);
148                 send = sie>cend || sie<0?cend:sie;  // if the Semicolon is after the comma, or non-existent, use comma end, else keep
149                 while (send>sis && Character.isSpaceChar(bytes[send-1]))--send;
150                 if (name==null) { // first entry in Comma set is the name, not a property
151                     name = new String(bytes,sis,send-sis);
152                 } else { // We've looped past the first Semi, now process as properties
153                     // If there are additional elements (more entities within Semi Colons)
154                     // apply Properties
155                     int eq = cntnt.indexOf('=',sis);
156                     if (eq>sis && eq<send) {
157                         props.add(new String(bytes,sis,eq-sis));
158                         props.add(new String(bytes,eq+1,send-(eq+1)));
159                     }
160                 }
161                 // End Property
162             } while (sie<=cend && sie>=cis); // End SEMI processing
163             // Now evaluate Comma set and return if true
164             if (eval(code,name,props))return true; // else loop again to check next comma
165         } while (cie>=0); // loop to next comma
166         return false; // didn't get even one match
167     }
168
169 }