Imported Upstream version 16.3.2
[platform/upstream/libzypp.git] / zypp / PluginFrame.cc
1 /*---------------------------------------------------------------------\
2 |                          ____ _   __ __ ___                          |
3 |                         |__  / \ / / . \ . \                         |
4 |                           / / \ V /|  _/  _/                         |
5 |                          / /__ | | | | | |                           |
6 |                         /_____||_| |_| |_|                           |
7 |                                                                      |
8 \---------------------------------------------------------------------*/
9 /** \file       zypp/PluginFrame.cc
10  *
11 */
12 #include <iostream>
13 #include "zypp/base/LogTools.h"
14 #include "zypp/base/String.h"
15
16 #include "zypp/PluginFrame.h"
17
18 using std::endl;
19
20 #undef  ZYPP_BASE_LOGGER_LOGGROUP
21 #define ZYPP_BASE_LOGGER_LOGGROUP "zypp::plugin"
22
23 ///////////////////////////////////////////////////////////////////
24 namespace zypp
25 { /////////////////////////////////////////////////////////////////
26
27   ///////////////////////////////////////////////////////////////////
28   //
29   //    CLASS NAME : PluginFrame::Impl
30   //
31   /** PluginFrame implementation. */
32   struct PluginFrame::Impl
33   {
34     public:
35       Impl()
36       {}
37
38       Impl( const std::string & command_r )
39       { setCommand( command_r ); }
40
41       Impl( const std::string & command_r, const std::string & body_r )
42         : _body( body_r )
43       { setCommand( command_r ); }
44
45       Impl( const std::string & command_r, HeaderInitializerList contents_r )
46       { setCommand( command_r ); addHeader( contents_r ); }
47
48       Impl( const std::string & command_r, const std::string & body_r, HeaderInitializerList contents_r )
49         : _body( body_r )
50       { setCommand( command_r ); addHeader( contents_r ); }
51
52       Impl( std::istream & stream_r );
53
54     public:
55       bool empty() const
56       { return _command.empty() && _body.empty(); }
57
58       const std::string & command() const
59       { return _command; }
60
61       void setCommand( const std::string & command_r )
62       {
63         if ( command_r.find( '\n' ) != std::string::npos )
64           ZYPP_THROW( PluginFrameException( "Multiline command", command_r ) );
65         _command = command_r;
66       }
67
68       const std::string & body() const
69       { return _body; }
70
71       std::string & bodyRef()
72       { return _body; }
73
74       void setBody( const std::string & body_r )
75       { _body = body_r; }
76
77     public:
78       typedef std::pair<HeaderListIterator,HeaderListIterator> constKeyRange;
79       typedef std::pair<HeaderList::iterator,HeaderList::iterator> KeyRange;
80
81       HeaderList & headerList()
82       { return _header; }
83
84       const HeaderList & headerList() const
85       { return _header; }
86
87       const std::string & getHeader( const std::string & key_r ) const
88       {
89         constKeyRange r( _header.equal_range( key_r ) );
90         if ( r.first == r.second )
91           ZYPP_THROW( PluginFrameException( "No value for key", key_r ) );
92         const std::string & ret( r.first->second );
93         if ( ++r.first != r.second )
94           ZYPP_THROW( PluginFrameException( "Multiple values for key", key_r ) );
95         return ret;
96       }
97
98       const std::string & getHeader( const std::string & key_r, const std::string & default_r ) const
99       {
100         constKeyRange r( _header.equal_range( key_r ) );
101         if ( r.first == r.second )
102           return default_r;
103         const std::string & ret( r.first->second );
104         if ( ++r.first != r.second )
105           ZYPP_THROW( PluginFrameException( "Multiple values for key", key_r ) );
106         return ret;
107       }
108
109       const std::string & getHeaderNT( const std::string & key_r, const std::string & default_r ) const
110       {
111         HeaderListIterator iter( _header.find( key_r ) );
112         return iter != _header.end() ? iter->second : default_r;
113       }
114
115       HeaderList::value_type mkHeaderPair( const std::string & key_r, const std::string & value_r )
116       {
117         if ( key_r.find_first_of( ":\n" ) != std::string::npos )
118           ZYPP_THROW( PluginFrameException( "Illegal char in header key", key_r ) );
119         if ( value_r.find_first_of( ":\n" ) != std::string::npos )
120           ZYPP_THROW( PluginFrameException( "Illegal char in header value", value_r ) );
121         return HeaderList::value_type( key_r, value_r );
122       }
123
124       void setHeader( const std::string & key_r, const std::string & value_r )
125       {
126         clearHeader( key_r );
127         addHeader( key_r, value_r );
128       }
129
130       void addHeader( const std::string & key_r, const std::string & value_r )
131       {
132         _header.insert( mkHeaderPair( key_r, value_r ) );
133       }
134
135       void addHeader( HeaderInitializerList contents_r )
136       {
137         for ( const auto & el : contents_r )
138           addHeader( el.first, el.second );
139       }
140
141       void clearHeader( const std::string & key_r )
142       {
143         _header.erase( key_r );
144       }
145
146     public:
147       std::ostream & writeTo( std::ostream & stream_r ) const;
148
149     private:
150       std::string _command;
151       std::string _body;
152       HeaderList  _header;
153
154     public:
155       /** Offer default Impl. */
156       static shared_ptr<Impl> nullimpl()
157       {
158         static shared_ptr<Impl> _nullimpl( new Impl );
159         return _nullimpl;
160       }
161     private:
162       friend Impl * rwcowClone<Impl>( const Impl * rhs );
163       /** clone for RWCOW_pointer */
164       Impl * clone() const
165       { return new Impl( *this ); }
166   };
167   ///////////////////////////////////////////////////////////////////
168
169   /** \relates PluginFrame::Impl Stream output */
170   inline std::ostream & operator<<( std::ostream & str, const PluginFrame::Impl & obj )
171   {
172     return str << "PluginFrame[" << obj.command() << "](" << obj.headerList().size() << "){" << obj.body().size() << "}";
173   }
174
175   PluginFrame::Impl::Impl( std::istream & stream_r )
176   {
177     //DBG << "Parse from " << stream_r << endl;
178     if ( ! stream_r )
179       ZYPP_THROW( PluginFrameException( "Bad Stream" ) );
180
181     // JFYI: stream status after getline():
182     //  Bool  | Bits
183     //  ------|---------------
184     //  true  | [g___] >FOO< : FOO line was \n-terminated
185     //  true  | [_e__] >BAA< : BAA before EOF, but not \n-terminated
186     //  false | [_eF_] ><    : No valid data to consume
187
188     //command
189     _command = str::getline( stream_r );
190     if ( ! stream_r.good() )
191       ZYPP_THROW( PluginFrameException( "Missing NL after command" ) );
192
193     // header
194     do {
195       std::string data = str::getline( stream_r );
196       if ( ! stream_r.good() )
197         ZYPP_THROW( PluginFrameException( "Missing NL after header" ) );
198
199       if ( data.empty() )
200         break;  // --> empty line sep. header and body
201
202       std::string::size_type sep( data.find( ':') );
203       if ( sep ==  std::string::npos )
204         ZYPP_THROW( PluginFrameException( "Missing colon in header" ) );
205
206       _header.insert( HeaderList::value_type( data.substr(0,sep), data.substr(sep+1) ) );
207     } while ( true );
208
209     // data
210     _body = str::receiveUpTo( stream_r, '\0' );
211     if ( ! stream_r.good() )
212       ZYPP_THROW( PluginFrameException( "Missing NUL after body" ) );
213   }
214
215   std::ostream & PluginFrame::Impl::writeTo( std::ostream & stream_r ) const
216   {
217     //DBG << "Write " << *this << " to " << stream_r << endl;
218     if ( ! stream_r )
219       ZYPP_THROW( PluginFrameException( "Bad Stream" ) );
220
221     // command
222     stream_r << _command << endl;
223     // header
224     for_( it, _header.begin(), _header.end() )
225       stream_r << it->first << ':' << it->second << endl;
226     // body
227     stream_r << endl
228              << _body << '\0';
229
230     if ( ! stream_r )
231       ZYPP_THROW( PluginFrameException( "Write error" ) );
232     return stream_r;
233   }
234
235   ///////////////////////////////////////////////////////////////////
236   //
237   //    CLASS NAME : PluginFrame
238   //
239   ///////////////////////////////////////////////////////////////////
240
241   const std::string & PluginFrame::ackCommand()
242   {
243     static std::string _val( "ACK" );
244     return _val;
245   }
246
247   const std::string & PluginFrame::errorCommand()
248   {
249     static std::string _val( "ERROR" );
250     return _val;
251   }
252
253   const std::string & PluginFrame::enomethodCommand()
254   {
255     static std::string _val( "_ENOMETHOD" );
256     return _val;
257   }
258
259   PluginFrame::PluginFrame()
260     : _pimpl( Impl::nullimpl() )
261   {}
262
263   PluginFrame::PluginFrame( const std::string & command_r )
264     : _pimpl( new Impl( command_r ) )
265   {}
266
267   PluginFrame::PluginFrame( const std::string & command_r, const std::string & body_r )
268     : _pimpl( new Impl( command_r, body_r ) )
269   {}
270
271   PluginFrame::PluginFrame( const std::string & command_r, HeaderInitializerList contents_r )
272     : _pimpl( new Impl( command_r, contents_r ) )
273   {}
274
275   PluginFrame::PluginFrame( const std::string & command_r, const std::string & body_r, HeaderInitializerList contents_r )
276     : _pimpl( new Impl( command_r, body_r, contents_r ) )
277   {}
278
279   PluginFrame::PluginFrame( std::istream & stream_r )
280     : _pimpl( new Impl( stream_r ) )
281   {}
282
283   bool PluginFrame::empty() const
284   { return _pimpl->empty(); }
285
286   const std::string & PluginFrame::command() const
287   { return _pimpl->command(); }
288
289   void  PluginFrame::setCommand( const std::string & command_r )
290   { _pimpl->setCommand( command_r ); }
291
292   const std::string & PluginFrame::body() const
293   { return _pimpl->body(); }
294
295   std::string & PluginFrame::bodyRef()
296   { return _pimpl->bodyRef(); }
297
298   void  PluginFrame::setBody( const std::string & body_r )
299   { _pimpl->setBody( body_r ); }
300
301   std::ostream & PluginFrame::writeTo( std::ostream & stream_r ) const
302   { return _pimpl->writeTo( stream_r ); }
303
304   PluginFrame::HeaderList & PluginFrame::headerList()
305   { return _pimpl->headerList(); }
306
307   const PluginFrame::HeaderList & PluginFrame::headerList() const
308   { return _pimpl->headerList(); }
309
310   const std::string & PluginFrame::getHeader( const std::string & key_r ) const
311   { return _pimpl->getHeader( key_r ); }
312
313   const std::string & PluginFrame::getHeader( const std::string & key_r, const std::string & default_r ) const
314   { return _pimpl->getHeader( key_r, default_r ); }
315
316   const std::string & PluginFrame::getHeaderNT( const std::string & key_r, const std::string & default_r ) const
317   { return _pimpl->getHeaderNT( key_r, default_r ); }
318
319   void PluginFrame::setHeader( const std::string & key_r, const std::string & value_r )
320   { _pimpl->setHeader( key_r, value_r ); }
321
322   void PluginFrame::addHeader( const std::string & key_r, const std::string & value_r )
323   { _pimpl->addHeader( key_r, value_r ); }
324
325   void PluginFrame::addHeader( HeaderInitializerList contents_r )
326   { _pimpl->addHeader( contents_r ); }
327
328   void PluginFrame::clearHeader( const std::string & key_r )
329   { _pimpl->clearHeader( key_r ); }
330
331   ///////////////////////////////////////////////////////////////////
332
333   std::ostream & operator<<( std::ostream & str, const PluginFrame & obj )
334   { return str << *obj._pimpl; }
335
336   bool operator==( const PluginFrame & lhs, const PluginFrame & rhs )
337   {
338     return ( lhs._pimpl == rhs._pimpl )
339         || (( lhs.command() ==  rhs.command() ) && ( lhs.headerList() == rhs.headerList() ) && ( lhs.body() == rhs.body() ));
340   }
341
342   /////////////////////////////////////////////////////////////////
343 } // namespace zypp
344 ///////////////////////////////////////////////////////////////////