diff --git a/THIRDPARTYNOTICES b/THIRDPARTYNOTICES index c1f95911a76..afc0f830f7f 100644 --- a/THIRDPARTYNOTICES +++ b/THIRDPARTYNOTICES @@ -472,165 +472,6 @@ of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF - -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - -DEALINGS IN THE SOFTWARE. - -*** - -tokio-rs/tokio-service -Copyright (c) 2016 Alex Crichton - - - -Permission is hereby granted, free of charge, to any - -person obtaining a copy of this software and associated - -documentation files (the "Software"), to deal in the - -Software without restriction, including without - -limitation the rights to use, copy, modify, merge, - -publish, distribute, sublicense, and/or sell copies of - -the Software, and to permit persons to whom the Software - -is furnished to do so, subject to the following - -conditions: - - - -The above copyright notice and this permission notice - -shall be included in all copies or substantial portions - -of the Software. - - - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF - -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - -DEALINGS IN THE SOFTWARE. - -*** - -tokio-rs/tokio-proto -Copyright (c) 2016 Tokio contributors - - - -Permission is hereby granted, free of charge, to any - -person obtaining a copy of this software and associated - -documentation files (the "Software"), to deal in the - -Software without restriction, including without - -limitation the rights to use, copy, modify, merge, - -publish, distribute, sublicense, and/or sell copies of - -the Software, and to permit persons to whom the Software - -is furnished to do so, subject to the following - -conditions: - - - -The above copyright notice and this permission notice - -shall be included in all copies or substantial portions - -of the Software. - - - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF - -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED - -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A - -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT - -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR - -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER - -DEALINGS IN THE SOFTWARE. - -*** - -tokio-rs/tokio-core -Copyright (c) 2016 Alex Crichton - - - -Permission is hereby granted, free of charge, to any - -person obtaining a copy of this software and associated - -documentation files (the "Software"), to deal in the - -Software without restriction, including without - -limitation the rights to use, copy, modify, merge, - -publish, distribute, sublicense, and/or sell copies of - -the Software, and to permit persons to whom the Software - -is furnished to do so, subject to the following - -conditions: - - - -The above copyright notice and this permission notice - -shall be included in all copies or substantial portions - -of the Software. - - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED @@ -974,45 +815,27 @@ limitations under the License. *** -oftprops/hyperlocal -Copyright (c) 2015-2017 Doug Tangren - +softprops/hyperlocal +Copyright (c) 2015-2018 Doug Tangren Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *** @@ -1969,7 +1792,7 @@ DEALINGS IN THE SOFTWARE. *** -rust-lang-nursery/lasy-static.rs +rust-lang-nursery/lazy-static.rs Copyright (c) 2010 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -1995,7 +1818,7 @@ DEALINGS IN THE SOFTWARE. *** -rust-lang-nursery/bitflags +bitflags/bitflags Copyright (c) 2014 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -2312,26 +2135,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *** -pyfisch/rust-language-tags -Copyright (c) 2015 Pyfisch -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. - -*** - Portable.BouncyCastle @@ -2667,28 +2470,26 @@ EFFET JURIDIQUE. Le présent contrat décrit certains droits juridiques. Vous po *** mgeisler/textwrap -Copyright (c) 2017 Ryan Leckey -Permission is hereby granted, free of charge, to any -person obtaining a copy of this software and associated -documentation files (the "Software"), to deal in the -Software without restriction, including without -limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software -is furnished to do so, subject to the following -conditions: -The above copyright notice and this permission notice -shall be included in all copies or substantial portions -of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT -SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR -IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. + +Copyright (c) 2016 Martin Geisler + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. *** @@ -2898,7 +2699,7 @@ McMaster.Extensions.CommandLineUtils *** -kbknapp/clap-rs +clap-rs/clap The MIT License (MIT) Copyright (c) 2015-2016 Kevin B. Knapp Permission is hereby granted, free of charge, to any person obtaining a copy @@ -3693,30 +3494,26 @@ THE SOFTWARE. *** BurntSushi/rucd -This is free and unencumbered software released into the public domain. -Anyone is free to copy, modify, publish, use, compile, sell, or -distribute this software, either in source code form or as a compiled -binary, for any purpose, commercial or non-commercial, and by any -means. +Copyright (c) 2015 Andrew Gallant -In jurisdictions that recognize copyright laws, the author or authors -of this software dedicate any and all copyright interest in the -software to the public domain. We make this dedication for the benefit -of the public at large and to the detriment of our heirs and -successors. We intend this dedication to be an overt act of -relinquishment in perpetuity of all present and future rights to this -software under copyright law. +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. -For more information, please refer to +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. *** @@ -3749,7 +3546,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -scopegaurd +scopeguard Copyright (c) 2015 The Rust Project Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated @@ -4015,7 +3812,7 @@ For more information, please refer to *** -rust-Base64 +rust-base64 The MIT License (MIT) Copyright (c) 2015 Alice Maz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights @@ -4283,11 +4080,32 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** env_logger -Copyright (c) 2010 The Rust Project Developers -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. *** @@ -4506,16 +4324,6 @@ Please see the License for the specific language governing rights and limitation *** -scoped-tls -Copyright (c) 2014 Alex Crichton -Copyright 2014-2015 The Rust Project Developers -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, -including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*** - socket2-rs Copyright (c) 2014 Alex Crichton Copyright 2015-2016 The Rust Project Developers @@ -4525,14 +4333,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -tokio-signal -Copyright (c) 2016 Alex Crichton -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*** - thread_local Copyright 2017 Amanieu d'Antras Copyright (c) 2016 The Rust Project Developers @@ -4570,14 +4370,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -take -Copyright (c) 2016 Carl Lerche -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*** - itoa Copyright (c) 2016 Itoa Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: @@ -4592,7 +4384,8 @@ The compiler-builtins crate is dual licensed under both the University of Illino *** -Serde YAML +dtolnay/serde-yaml + Copyright (c) 2016 Serde YAML Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -4600,7 +4393,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -hyperium/HTTP +hyperium/http Copyright (c) 2017 http-rs authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -4717,7 +4510,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -Futures-rs +futures-rs Copyright (c) 2016 Alex Crichton Copyright (c) 2017 The Tokio Authors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: @@ -4749,7 +4542,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -Thread-ID +thread-id Copyright 2017 Ruud van Asseldonk Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. @@ -4765,14 +4558,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -relay -Copyright (c) 2017 Sean McArthur -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -*** - rust-fnv Copyright (c) 2017 Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: @@ -4781,105 +4566,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI *** -rust-smallvec -Mozilla Public License Version 2.0 -================================== -1. Definitions --------------- -1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. -1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. -1.3. "Contribution" means Covered Software of a particular Contributor. -1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. -1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. -1.6. "Executable Form" means any form of the work other than Source Code Form. -1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. -1.8. "License" means this document. -1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. -1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. -1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such -Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. -1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. -1.13. "Source Code Form" means the form of the work preferred for making modifications. -1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. -2. License Grants and Conditions --------------------------------- -2.1. Grants -Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: -(a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and -(b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. -2.2. Effective Date -The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. -2.3. Limitations on Grant Scope -The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: -(a) for any code that a Contributor has removed from Covered Software; or -(b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or -(c) under Patent Claims infringed by Covered Software in the absence of its Contributions. -This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). -2.4. Subsequent Licenses -No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). -2.5. Representation -Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. -2.6. Fair Use -This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. -2.7. Conditions -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. -3. Responsibilities -------------------- -3.1. Distribution of Source Form -All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. -3.2. Distribution of Executable Form -If You distribute Covered Software in Executable Form then: -(a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and -(b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. -3.3. Distribution of a Larger Work -You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). -3.4. Notices -You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. -3.5. Application of Additional Terms -You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. -4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- -If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. -5. Termination --------------- -5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. -5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. -************************************************************************ -6. Disclaimer of Warranty -Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. -************************************************************************ -7. Limitation of Liability -Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. -************************************************************************ -8. Litigation -------------- -Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. -9. Miscellaneous ----------------- -This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. -10. Versions of the License ---------------------------- -10.1. New Versions -Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. -10.2. Effect of New Versions -You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. -10.3. Modified Versions -If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses -If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. -Exhibit A - Source Code Form License Notice -------------------------------------------- -This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. -You may add additional accurate notices of copyright ownership. -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- -This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. - -*** - unicode-bidi Copyright 2015, The Servo Project Developers (Matt Brubeck and Behnam Esfahbod Copyright (c) 2015 The Rust Project Developers @@ -5011,107 +4697,6 @@ Use and transfer of Docker may be subject to certain restrictions by the United For more information, please see https://www.bis.doc.gov See also https://www.apache.org/dev/crypto.html and/or seek legal counsel. -*** - -The software may incorporate copyrighted material from third parties under open source licenses which require source code availability. Copies of these licenses are included below. You may find a copy of any Corresponding Source code if required by such licenses at http://3rdpartysource.microsoft.com. You may also obtain a copy of any Corresponding Source during the time period specified in the license by sending a check or money order for US$5.00 to: Source Code Compliance Team, Microsoft Corporation, 1 Microsoft Way, Redmond, WA 98052, USA. Please write “source code for [OSS PROJECT NAME]” in the memo line of your payment. Microsoft reserves all rights not expressly granted, whether by implication, estoppel or otherwise.? - -rust-smallvec -Mozilla Public License Version 2.0 -================================== -1. Definitions --------------- -1.1. "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns Covered Software. -1.2. "Contributor Version" means the combination of the Contributions of others (if any) used by a Contributor and that particular Contributor's Contribution. -1.3. "Contribution" means Covered Software of a particular Contributor. -1.4. "Covered Software" means Source Code Form to which the initial Contributor has attached the notice in Exhibit A, the Executable Form of such Source Code Form, and Modifications of such Source Code Form, in each case including portions thereof. -1.5. "Incompatible With Secondary Licenses" means (a) that the initial Contributor has attached the notice described in Exhibit B to the Covered Software; or (b) that the Covered Software was made available under the terms of version 1.1 or earlier of the License, but not also under the terms of a Secondary License. -1.6. "Executable Form" means any form of the work other than Source Code Form. -1.7. "Larger Work" means a work that combines Covered Software with other material, in a separate file or files, that is not Covered Software. -1.8. "License" means this document. -1.9. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently, any and all of the rights conveyed by this License. -1.10. "Modifications" means any of the following: (a) any file in Source Code Form that results from an addition to, deletion from, or modification of the contents of Covered Software; or (b) any new file in Source Code Form that contains any Covered Software. -1.11. "Patent Claims" of a Contributor means any patent claim(s), including without limitation, method, process, and apparatus claims, in any patent Licensable by such -Contributor that would be infringed, but for the grant of the License, by the making, using, selling, offering for sale, having made, import, or transfer of either its Contributions or its Contributor Version. -1.12. "Secondary License" means either the GNU General Public License, Version 2.0, the GNU Lesser General Public License, Version 2.1, the GNU Affero General Public License, Version 3.0, or any later versions of those licenses. -1.13. "Source Code Form" means the form of the work preferred for making modifications. -1.14. "You" (or "Your") means an individual or a legal entity exercising rights under this License. For legal entities, "You" includes any entity that controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. -2. License Grants and Conditions --------------------------------- -2.1. Grants -Each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license: -(a) under intellectual property rights (other than patent or trademark) Licensable by such Contributor to use, reproduce, make available, modify, display, perform, distribute, and otherwise exploit its Contributions, either on an unmodified basis, with Modifications, or as part of a Larger Work; and -(b) under Patent Claims of such Contributor to make, use, sell, offer for sale, have made, import, and otherwise transfer either its Contributions or its Contributor Version. -2.2. Effective Date -The licenses granted in Section 2.1 with respect to any Contribution become effective for each Contribution on the date the Contributor first distributes such Contribution. -2.3. Limitations on Grant Scope -The licenses granted in this Section 2 are the only rights granted under this License. No additional rights or licenses will be implied from the distribution or licensing of Covered Software under this License. Notwithstanding Section 2.1(b) above, no patent license is granted by a Contributor: -(a) for any code that a Contributor has removed from Covered Software; or -(b) for infringements caused by: (i) Your and any other third party's modifications of Covered Software, or (ii) the combination of its Contributions with other software (except as part of its Contributor Version); or -(c) under Patent Claims infringed by Covered Software in the absence of its Contributions. -This License does not grant any rights in the trademarks, service marks, or logos of any Contributor (except as may be necessary to comply with the notice requirements in Section 3.4). -2.4. Subsequent Licenses -No Contributor makes additional grants as a result of Your choice to distribute the Covered Software under a subsequent version of this License (see Section 10.2) or under the terms of a Secondary License (if permitted under the terms of Section 3.3). -2.5. Representation -Each Contributor represents that the Contributor believes its Contributions are its original creation(s) or it has sufficient rights to grant the rights to its Contributions conveyed by this License. -2.6. Fair Use -This License is not intended to limit any rights You have under applicable copyright doctrines of fair use, fair dealing, or other equivalents. -2.7. Conditions -Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in Section 2.1. -3. Responsibilities -------------------- -3.1. Distribution of Source Form -All distribution of Covered Software in Source Code Form, including any Modifications that You create or to which You contribute, must be under the terms of this License. You must inform recipients that the Source Code Form of the Covered Software is governed by the terms of this License, and how they can obtain a copy of this License. You may not attempt to alter or restrict the recipients' rights in the Source Code Form. -3.2. Distribution of Executable Form -If You distribute Covered Software in Executable Form then: -(a) such Covered Software must also be made available in Source Code Form, as described in Section 3.1, and You must inform recipients of the Executable Form how they can obtain a copy of such Source Code Form by reasonable means in a timely manner, at a charge no more than the cost of distribution to the recipient; and -(b) You may distribute such Executable Form under the terms of this License, or sublicense it under different terms, provided that the license for the Executable Form does not attempt to limit or alter the recipients' rights in the Source Code Form under this License. -3.3. Distribution of a Larger Work -You may create and distribute a Larger Work under terms of Your choice, provided that You also comply with the requirements of this License for the Covered Software. If the Larger Work is a combination of Covered Software with a work governed by one or more Secondary Licenses, and the Covered Software is not Incompatible With Secondary Licenses, this License permits You to additionally distribute such Covered Software under the terms of such Secondary License(s), so that the recipient of the Larger Work may, at their option, further distribute the Covered Software under the terms of either this License or such Secondary License(s). -3.4. Notices -You may not remove or alter the substance of any license notices (including copyright notices, patent notices, disclaimers of warranty, or limitations of liability) contained within the Source Code Form of the Covered Software, except that You may alter any license notices to the extent required to remedy known factual inaccuracies. -3.5. Application of Additional Terms -You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, You may do so only on Your own behalf, and not on behalf of any Contributor. You must make it absolutely clear that any such warranty, support, indemnity, or liability obligation is offered by You alone, and You hereby agree to indemnify every Contributor for any liability incurred by such Contributor as a result of warranty, support, -indemnity or liability terms You offer. You may include additional disclaimers of warranty and limitations of liability specific to any jurisdiction. -4. Inability to Comply Due to Statute or Regulation --------------------------------------------------- -If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Software due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be placed in a text file included with all distributions of the Covered Software under this License. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. -5. Termination --------------- -5.1. The rights granted under this License will terminate automatically if You fail to comply with any of its terms. However, if You become compliant, then the rights granted under this License from a particular Contributor are reinstated (a) provisionally, unless and until such Contributor explicitly and finally terminates Your grants, and (b) on an ongoing basis, if such Contributor fails to notify You of the non-compliance by some reasonable means prior to 60 days after You have come back into compliance. Moreover, Your grants from a particular Contributor are reinstated on an ongoing basis if such Contributor notifies You of the non-compliance by some reasonable means, this is the first time You have received notice of non-compliance with this License from such Contributor, and You become compliant prior to 30 days after Your receipt of the notice. -5.2. If You initiate litigation against any entity by asserting a patent infringement claim (excluding declaratory judgment actions, counter-claims, and cross-claims) alleging that a Contributor Version directly or indirectly infringes any patent, then the rights granted to You by any and all Contributors for the Covered Software under Section 2.1 of this License shall terminate. -5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or Your distributors under this License prior to termination shall survive termination. -************************************************************************ -6. Disclaimer of Warranty -Covered Software is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the Covered Software is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire risk as to the quality and performance of the Covered Software is with You. Should any Covered Software prove defective in any respect, You (not any Contributor) assume the cost of any necessary servicing, repair, or correction. This disclaimer of warranty constitutes an essential part of this License. No use of any Covered Software is authorized under this License except under this disclaimer. -************************************************************************ -7. Limitation of Liability -Under no circumstances and under no legal theory, whether tort (including negligence), contract, or otherwise, shall any Contributor, or anyone who distributes Covered Software as permitted above, be liable to You for any direct, indirect, special, incidental, or consequential damages of any character including, without limitation, damages for lost profits, loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses, even if such party shall have been informed of the possibility of such damages. This limitation of liability shall not apply to liability for death or personal injury resulting from such party's negligence to the extent applicable law prohibits such limitation. Some jurisdictions do not allow the exclusion or limitation of incidental or consequential damages, so this exclusion and limitation may not apply to You. -************************************************************************ -8. Litigation -------------- -Any litigation relating to this License may be brought only in the courts of a jurisdiction where the defendant maintains its principal place of business and such litigation shall be governed by laws of that jurisdiction, without reference to its conflict-of-law provisions. Nothing in this Section shall prevent a party's ability to bring cross-claims or counter-claims. -9. Miscellaneous ----------------- -This License represents the complete agreement concerning the subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not be used to construe this License against a Contributor. -10. Versions of the License ---------------------------- -10.1. New Versions -Mozilla Foundation is the license steward. Except as provided in Section 10.3, no one other than the license steward has the right to modify or publish new versions of this License. Each version will be given a distinguishing version number. -10.2. Effect of New Versions -You may distribute the Covered Software under the terms of the version of the License under which You originally received the Covered Software, or under the terms of any subsequent version published by the license steward. -10.3. Modified Versions -If you create software not governed by this License, and you want to create a new license for such software, you may create and use a modified version of this License if you rename the license and remove any references to the name of the license steward (except to note that such modified license differs from this License). -10.4. Distributing Source Code Form that is Incompatible With Secondary Licenses -If You choose to distribute Source Code Form that is Incompatible With Secondary Licenses under the terms of this version of the License, the notice described in Exhibit B of this License must be attached. -Exhibit A - Source Code Form License Notice -------------------------------------------- -This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. -If it is not possible or desirable to put the notice in a particular file, then You may include the notice in a location (such as a LICENSE file in a relevant directory) where a recipient would be likely to look for such a notice. -You may add additional accurate notices of copyright ownership. -Exhibit B - "Incompatible With Secondary Licenses" Notice ---------------------------------------------------------- -This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0. - *** curl-sys @@ -5394,3 +4979,320 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *** + +bluss/indexmap + +Copyright (c) 2016--2017 Ulrik Sverdrup "bluss" + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*** + +BurntSushi/termcolor + +Copyright (c) 2015 Andrew Gallant + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*** + +carllerche/h2 + +Copyright (c) 2017 h2 authors + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*** + +carllerche/string + +Copyright (c) 2018 Carl Lerche + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*** + +contain-rs/linked-hash-map + +Copyright (c) 2015 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*** + +Kimundi/rustc-version-rs + +Copyright (c) 2016 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*** + +seanmonstar/try-lock + +Copyright (c) 2018 Sean McArthur +Copyright (c) 2016 Alex Crichton + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*** + +seanmonstar/want + +Copyright (c) 2018 Sean McArthur + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +*** + +sfackler/typed-headers + +Copyright (c) 2017 The tokio-io-timeout Developers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*** + +steveklabnik/semver + +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*** + +steveklabnik/semver-parser + +Copyright (c) 2016 Steve Klabnik + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +*** + +tafia/hyper-proxy + +Copyright (c) 2017 Johann Tuffe + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/edgelet/Cargo.lock b/edgelet/Cargo.lock index 660286afdcc..5a641541f31 100644 --- a/edgelet/Cargo.lock +++ b/edgelet/Cargo.lock @@ -75,11 +75,6 @@ dependencies = [ "safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "bitflags" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "bitflags" version = "1.0.3" @@ -198,16 +193,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "core-foundation" -version = "0.2.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "core-foundation-sys" -version = "0.2.3" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -215,21 +210,21 @@ dependencies = [ [[package]] name = "crossbeam-deque" -version = "0.3.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "crossbeam-epoch" -version = "0.4.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -237,19 +232,8 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "crossbeam-utils" -version = "0.3.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "crypto-mac" @@ -273,14 +257,14 @@ name = "docker" version = "0.1.0" dependencies = [ "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -293,18 +277,16 @@ dependencies = [ "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "edgelet-core 0.1.0", "edgelet-http 0.1.0", - "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -322,18 +304,16 @@ dependencies = [ "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "consistenttime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -348,17 +328,18 @@ dependencies = [ "edgelet-http 0.1.0", "edgelet-test-utils 0.1.0", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -369,7 +350,7 @@ dependencies = [ "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "edgelet-core 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "hsm 0.1.0", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -384,19 +365,19 @@ dependencies = [ "edgelet-core 0.1.0", "edgelet-test-utils 0.1.0", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "hyper-named-pipe 0.1.0", - "hyper-proxy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "hyperlocal 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-proxy 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyperlocal 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -406,10 +387,10 @@ dependencies = [ "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "systemd 0.1.0", "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-named-pipe 0.1.0", - "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -423,18 +404,17 @@ dependencies = [ "edgelet-http 0.1.0", "edgelet-iothub 0.1.0", "edgelet-test-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "management 0.1.0", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -445,17 +425,15 @@ dependencies = [ "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "edgelet-core 0.1.0", - "edgelet-hsm 0.1.0", "edgelet-http 0.1.0", "edgelet-test-utils 0.1.0", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "workload 0.1.0", ] @@ -470,15 +448,16 @@ dependencies = [ "edgelet-core 0.1.0", "edgelet-http 0.1.0", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "iothubservice 0.1.0", "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -487,26 +466,26 @@ name = "edgelet-test-utils" version = "0.1.0" dependencies = [ "edgelet-core 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyperlocal 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "hyperlocal 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "edgelet-utils" version = "0.1.0" dependencies = [ - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -519,7 +498,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -534,21 +513,22 @@ dependencies = [ [[package]] name = "failure" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -590,7 +570,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "futures" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -598,7 +578,7 @@ name = "futures-cpupool" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -611,9 +591,21 @@ dependencies = [ ] [[package]] -name = "hex" -version = "0.2.0" +name = "h2" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "hex" @@ -633,7 +625,7 @@ dependencies = [ name = "hsm" version = "0.1.0" dependencies = [ - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "hsm-sys 0.1.0", ] @@ -647,11 +639,12 @@ dependencies = [ [[package]] name = "http" -version = "0.1.5" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -669,27 +662,28 @@ dependencies = [ [[package]] name = "hyper" -version = "0.11.25" +version = "0.12.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -698,59 +692,57 @@ version = "0.1.0" dependencies = [ "edgelet-test-utils 0.1.0", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-named-pipe 0.1.0", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyper-proxy" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-tls 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyper-tls" -version = "0.1.3" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hyperlocal" -version = "0.4.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -763,6 +755,11 @@ dependencies = [ "unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "indexmap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "iotedge" version = "0.1.0" @@ -773,14 +770,11 @@ dependencies = [ "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", "edgelet-core 0.1.0", "edgelet-http-mgmt 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "management 0.1.0", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "tabwriter 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -802,21 +796,22 @@ dependencies = [ "edgelet-test-utils 0.1.0", "edgelet-utils 0.1.0", "env_logger 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "hsm 0.1.0", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "iothubservice 0.1.0", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "provisioning 0.1.0", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-signal 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-signal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "url_serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "version-compare 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -831,18 +826,17 @@ version = "0.1.0" dependencies = [ "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.31.2 (registry+https://github.com/rust-lang/crates.io-index)", - "edgelet-core 0.1.0", "edgelet-http 0.1.0", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -869,11 +863,6 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "language-tags" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "lazy_static" version = "0.2.11" @@ -910,15 +899,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "log" -version = "0.4.1" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -929,14 +910,14 @@ name = "management" version = "0.1.0" dependencies = [ "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -993,10 +974,10 @@ dependencies = [ "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1005,7 +986,7 @@ name = "mio-named-pipes" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1013,9 +994,10 @@ dependencies = [ [[package]] name = "mio-uds" -version = "0.6.4" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1042,16 +1024,18 @@ dependencies = [ [[package]] name = "native-tls" -version = "0.1.5" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)", - "schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.36 (registry+https://github.com/rust-lang/crates.io-index)", + "schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1120,19 +1104,25 @@ dependencies = [ [[package]] name = "openssl" -version = "0.9.24" +version = "0.10.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "openssl-sys 0.9.30 (registry+https://github.com/rust-lang/crates.io-index)", + "openssl-sys 0.9.36 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "openssl-probe" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "openssl-sys" -version = "0.9.30" +version = "0.9.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1159,6 +1149,14 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "provisioning" version = "0.1.0" @@ -1170,17 +1168,16 @@ dependencies = [ "edgelet-hsm 0.1.0", "edgelet-http 0.1.0", "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "hsm 0.1.0", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1189,11 +1186,6 @@ name = "quick-error" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "quote" version = "0.5.2" @@ -1203,13 +1195,11 @@ dependencies = [ ] [[package]] -name = "rand" -version = "0.3.22" +name = "quote" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1289,14 +1279,6 @@ dependencies = [ "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "relay" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "remove_dir_all" version = "0.5.1" @@ -1310,6 +1292,14 @@ name = "rustc-demangle" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "safemem" version = "0.2.0" @@ -1317,18 +1307,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "schannel" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "scoped-tls" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "scopeguard" version = "0.3.3" @@ -1336,24 +1321,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "security-framework" -version = "0.1.16" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", + "security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "security-framework-sys" -version = "0.1.16" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "serde" version = "0.8.23" @@ -1438,17 +1436,7 @@ dependencies = [ [[package]] name = "slab" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "slab" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "smallvec" -version = "0.2.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -1462,19 +1450,14 @@ dependencies = [ ] [[package]] -name = "strsim" -version = "0.7.0" +name = "string" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "syn" -version = "0.11.11" +name = "strsim" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "syn" @@ -1487,30 +1470,34 @@ dependencies = [ ] [[package]] -name = "synom" -version = "0.11.3" +name = "syn" +version = "0.14.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "synstructure" -version = "0.6.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "systemd" version = "0.1.0" dependencies = [ - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1522,11 +1509,6 @@ dependencies = [ "unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "take" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "tempdir" version = "0.3.7" @@ -1612,119 +1594,109 @@ dependencies = [ [[package]] name = "tokio" -version = "0.1.5" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-threadpool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-timer 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "tokio-core" -version = "0.1.17" +name = "tokio-codec" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-current-thread" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-executor" -version = "0.1.2" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tokio-fs" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-io" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-named-pipe" version = "0.1.0" dependencies = [ - "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tokio-proto" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "tokio-reactor" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-service" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-signal" -version = "0.1.5" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1734,53 +1706,46 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-threadpool" -version = "0.1.2" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-timer" -version = "0.1.2" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "tokio-timer" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-tls" -version = "0.1.4" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1789,27 +1754,27 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tokio-uds" -version = "0.1.7" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", - "mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1820,6 +1785,23 @@ dependencies = [ "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "try-lock" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "typed-headers" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "typenum" version = "1.10.0" @@ -1856,11 +1838,6 @@ name = "unicode-width" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.1.0" @@ -1928,6 +1905,16 @@ name = "void" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "want" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", + "try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "widestring" version = "0.3.0" @@ -1938,8 +1925,8 @@ name = "win-logger" version = "0.1.0" dependencies = [ "edgelet-utils 0.1.0", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2004,14 +1991,14 @@ name = "workload" version = "0.1.0" dependencies = [ "base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)", - "hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2042,7 +2029,6 @@ dependencies = [ "checksum backtrace 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe525f66f42d207968308ee86bc2dd60aa5fab535b22e616323a173d097d8e" "checksum backtrace-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "44585761d6161b0f57afc49482ab6bd067e4edef48c12a152c237eb0203f7661" "checksum base64 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9263aa6a38da271eec5c91a83ce1e800f093c8535788d403d626d8d5c3f8f007" -"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5" "checksum bitflags 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d0c54bb8f454c567f21197eefcdbf5679d0bd99f2ddbe52e84c77061952e6789" "checksum block-buffer 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" "checksum byte-tools 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" @@ -2058,51 +2044,49 @@ dependencies = [ "checksum config 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e595d1735d8ab6b04906bbdcfc671cce2a5e609b6f8e92865e67331cc2f41ba4" "checksum consistenttime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6a079bddaa385eab2a88dc5816a378921852ab3af6646748da14681b2facf502" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" -"checksum core-foundation 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "25bfd746d203017f7d5cbd31ee5d8e17f94b6521c7af77ece6c9e4b2d4b16c67" -"checksum core-foundation-sys 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "065a5d7ffdcbc8fa145d6f0746f3555025b9097a9e9cda59f7467abae670c78d" -"checksum crossbeam-deque 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c1bdc73742c36f7f35ebcda81dbb33a7e0d33757d03a06d9ddca762712ec5ea2" -"checksum crossbeam-epoch 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b4e2817eb773f770dcb294127c011e22771899c21d18fce7dd739c0b9832e81" -"checksum crossbeam-utils 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2760899e32a1d58d5abb31129f8fae5de75220bc2176e77ff7c627ae45c918d9" -"checksum crossbeam-utils 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d636a8b3bcc1b409d7ffd3facef8f21dcb4009626adbd0c5e6c4305c07253c7b" +"checksum core-foundation 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "286e0b41c3a20da26536c6000a280585d519fd07b3956b43aed8a79e9edce980" +"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" +"checksum crossbeam-deque 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3486aefc4c0487b9cb52372c97df0a48b8c249514af1ee99703bf70d2f2ceda1" +"checksum crossbeam-epoch 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30fecfcac6abfef8771151f8be4abc9e4edc112c2bcb233314cafde2680536e9" +"checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crypto-mac 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0999b4ff4d3446d4ddb19a63e9e00c1876e75cd7000d20e57a693b4b3f08d958" "checksum digest 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "00a49051fef47a72c9623101b19bd71924a45cca838826caae3eaa4d00772603" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum env_logger 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "00c45cec4cde3daac5f036c74098b4956151525cdf360cff5ee0092c98823e54" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" -"checksum failure 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "934799b6c1de475a012a02dab0ace1ace43789ee4b99bcfbf1a2e3e8ced5de82" -"checksum failure_derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c7cdda555bb90c9bb67a3b670a0f42de8e73f5981524123ad8578aafec8ddb8b" +"checksum failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7efb22686e4a466b1ec1a15c2898f91fa9cb340452496dca654032de20ff95b9" +"checksum failure_derive 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "946d0e98a50d9831f5d589038d2ca7f8f455b1c21028c0db0e84116a12696426" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" "checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" "checksum foreign-types-shared 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" -"checksum futures 0.1.21 (registry+https://github.com/rust-lang/crates.io-index)" = "1a70b146671de62ec8c8ed572219ca5d594d9b06c0b364d5e67b722fc559b48c" +"checksum futures 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)" = "0c84b40c7e2de99ffd70602db314a7a8c26b2b3d830e6f7f7a142a8860ab3ca4" "checksum futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "ab90cde24b3319636588d0c35fe03b1333857621051837ed769faefb4c2162e4" "checksum generic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ef25c5683767570c2bbd7deba372926a55eaae9982d7726ee2a1050239d45b9d" -"checksum hex 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d6a22814455d41612f41161581c2883c0c6a1c41852729b17d5ed88f01e153aa" +"checksum h2 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "a27e7ed946e8335bdf9a191bc1b9b14a03ba822d013d2f58437f4fabcbd7fc2c" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hmac 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44f3bdb08579d99d7dc761c0e266f13b5f2ab8c8c703b9fc9ef333cd8f48f55e" -"checksum http 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "75df369fd52c60635208a4d3e694777c099569b3dcf4844df8f652dc004644ab" +"checksum http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "24f58e8c2d8e886055c3ead7b28793e1455270b5fb39650984c224bc538ba581" "checksum httparse 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2f407128745b78abc95c0ffbe4e5d37427fdc0d45470710cfef8c44522a2e37" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" -"checksum hyper 0.11.25 (registry+https://github.com/rust-lang/crates.io-index)" = "549dbb86397490ce69d908425b9beebc85bbaad25157d67479d4995bb56fdf9a" -"checksum hyper-proxy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44f0925de2747e481e6e477dd212c25e8f745567f02f6182e04d27b97c3fbece" -"checksum hyper-tls 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a5aa51f6ae9842239b0fac14af5f22123b8432b4cc774a44ff059fcba0f675ca" -"checksum hyperlocal 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4a5af903b230fd1ee48990928c2cfaf47a3d45bbf1caa4f661342e8be11a4ac6" +"checksum hyper 0.12.10 (registry+https://github.com/rust-lang/crates.io-index)" = "529d00e4c998cced1a15ffd53bbe203917b39ed6071281c16184ab0014ca6ff3" +"checksum hyper-proxy 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1ca88dbc8a46e9a7530321ae8196527673d24f6ad08ce5b35078fe6a7d4001c6" +"checksum hyper-tls 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "caaee4dea92794a9e697038bd401e264307d1f22c883dbcb6f6618ba0d3b3bd3" +"checksum hyperlocal 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d063d6d5658623c6ef16f452e11437c0e7e23a6d327470573fe78892dafbc4fb" "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" +"checksum indexmap 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08173ba1e906efb6538785a8844dd496f5d34f0a2d88038e95195172fc667220" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itoa 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c069bbec61e1ca5a596166e55dfe4773ff745c3d16b700013bcaff9a6df2c682" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -"checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)" = "b685088df2b950fccadf07a7187c8ef846a959c142338a48f9dc0b94517eb5f1" "checksum linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d262045c5b87c0861b3f004610afd0e2c851e2908d08b6c870cbb9d5f494ecd" "checksum linked-hash-map 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "70fb39025bc7cdd76305867c4eccf2f2dcf6e9a57f5b21a93e1c2d86cd03ec9e" -"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" -"checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" +"checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" "checksum matches 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "100aabe6b8ff4e4a7e32c1c13523379802df0772b82466207ac25b013f193376" "checksum memchr 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d8b629fb514376c675b98c1421e80b151d3817ac42d7c667717d282761418d20" "checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" @@ -2111,10 +2095,10 @@ dependencies = [ "checksum mime 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e2e00e17be181010a91dbfefb01660b17311059dc8c7f48b9017677721e732bd" "checksum mio 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "6d771e3ef92d58a8da8df7d6976bfca9371ed1de6619d9d5a5ce5b1f29b85bfe" "checksum mio-named-pipes 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f5e374eff525ce1c5b7687c4cef63943e7686524a387933ad27ca7ec43779cb3" -"checksum mio-uds 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1731a873077147b626d89cc6c2a0db6288d607496c5d10c0cfcf3adc697ec673" +"checksum mio-uds 0.6.7 (registry+https://github.com/rust-lang/crates.io-index)" = "966257a94e196b11bb43aca423754d87429960a768de9414f3691d6957abf125" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum miow 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9224c91f82b3c47cf53dcf78dfaa20d6888fbcc5d272d5f2fcdf8a697f3c987d" -"checksum native-tls 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f74dbadc8b43df7864539cedb7bc91345e532fdd913cfdc23ad94f4d2d40fbc0" +"checksum native-tls 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8b0a7bd714e83db15676d31caf968ad7318e9cc35f93c85a90231c8f22867549" "checksum net2 0.2.32 (registry+https://github.com/rust-lang/crates.io-index)" = "9044faf1413a1057267be51b5afba8eb1090bd2231c693664aa1db716fe1eae0" "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "9a2228dca57108069a5262f2ed8bd2e82496d2e074a06d1ccc7ce1687b6ae0a2" @@ -2123,15 +2107,16 @@ dependencies = [ "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dee092fcdf725aee04dd7da1d21debff559237d49ef1cb3e69bcb8ece44c7364" "checksum num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c51a3322e4bca9d212ad9a158a02abc6934d005490c054a2778df73a70aa0a30" -"checksum openssl 0.9.24 (registry+https://github.com/rust-lang/crates.io-index)" = "a3605c298474a3aa69de92d21139fb5e2a81688d308262359d85cdd0d12a7985" -"checksum openssl-sys 0.9.30 (registry+https://github.com/rust-lang/crates.io-index)" = "73ae718c3562989cd3a0a5c26610feca02f8116822f6f195e6cf4887481e57f5" +"checksum openssl 0.10.12 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2e79eede055813a3ac52fb3915caf8e1c9da2dec1587871aec9f6f7b48508d" +"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" +"checksum openssl-sys 0.9.36 (registry+https://github.com/rust-lang/crates.io-index)" = "409d77eeb492a1aebd6eb322b2ee72ff7c7496b4434d98b3bf8be038755de65e" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pkg-config 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "110d5ee3593dbb73f56294327fe5668bcc997897097cbc76b51e7aed3f52452f" "checksum proc-macro2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1b06e2f335f48d24442b35a19df506a835fb3547bc3c06ef27340da9acf5cae7" +"checksum proc-macro2 0.4.19 (registry+https://github.com/rust-lang/crates.io-index)" = "ffe022fb8c8bd254524b0b3305906c1921fa37a84a644e29079a9e62200c3901" "checksum quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eda5fe9b71976e62bc81b781206aaa076401769b2143379d3eb2118388babac4" -"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" "checksum quote 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9949cfe66888ffe1d53e6ec9d9f3b70714083854be20fd5e271b232a017401e8" -"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1" +"checksum quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dd636425967c33af890042c483632d33fa7a18f19ad1d7ea72e8998c6ef8dea5" "checksum rand 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "eba5f8cb59cc50ed56be8880a5c7b496bfd9bd26394e176bc67884094145c2c5" "checksum rand 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "12397506224b2f93e6664ffc4f664b29be8208e5157d3d90b44f09b5fae470ea" "checksum rand_core 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "edecf0f94da5551fc9b492093e30b041a891657db7940ee221f9d2f66e82eef2" @@ -2141,15 +2126,16 @@ dependencies = [ "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" "checksum regex-syntax 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f9ec002c35e86791825ed294b50008eea9ddfc8def4420124fbc6b08db834957" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" -"checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum rustc-demangle 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11fb43a206a04116ffd7cfcf9bcb941f8eb6cc7ff667272246b0a1c74259a3cb" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" -"checksum schannel 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "85fd9df495640643ad2d00443b3d78aae69802ad488debab4f1dd52fc1806ade" -"checksum scoped-tls 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8674d439c964889e2476f474a3bf198cc9e199e77499960893bac5de7e9218a4" +"checksum schannel 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "dc1fabf2a7b6483a141426e1afd09ad543520a77ac49bd03c286e7696ccfd77f" "checksum scopeguard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "94258f53601af11e6a49f722422f6e3425c52b06245a5cf9bc09908b174f5e27" -"checksum security-framework 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "dfa44ee9c54ce5eecc9de7d5acbad112ee58755239381f687e564004ba4a2332" -"checksum security-framework-sys 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "5421621e836278a0b139268f36eee0dc7e389b784dc3f79d8f11aabadf41bead" +"checksum security-framework 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "697d3f3c23a618272ead9e1fb259c1411102b31c6af8b93f1d64cca9c3b0e8e0" +"checksum security-framework-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab01dfbe5756785b5b4d46e0289e5a18071dfa9a7c2b24213ea00b9ef9b665bf" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" "checksum serde 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" "checksum serde 1.0.43 (registry+https://github.com/rust-lang/crates.io-index)" = "0c855d888276f20d140223bd06515e5bf1647fd6d02593cb5792466d9a8ec2d0" "checksum serde-hjson 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a2376ebb8976138927f48b49588ef73cde2f6591b8b3df22f4063e0f27b9bec" @@ -2159,17 +2145,14 @@ dependencies = [ "checksum serde_test 0.8.23 (registry+https://github.com/rust-lang/crates.io-index)" = "110b3dbdf8607ec493c22d5d947753282f3bae73c0f56d322af1e8c78e4c23d5" "checksum serde_yaml 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "107bb818146aaf922e7bbcf6a940f1db2f0dcf381779b451e400331b2c6f86db" "checksum sha2 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9eb6be24e4c23a84d7184280d2722f7f2731fcdd4a9d886efbfe4413e4847ea0" -"checksum slab 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b4fcaed89ab08ef143da37bc52adbcc04d4a69014f4c1208d6b51f0c47bc23" -"checksum slab 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdeff4cd9ecff59ec7e3744cbca73dfe5ac35c2aedb2cfba8a1c715a18912e9d" -"checksum smallvec 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c8cbcd6df1e117c2210e13ab5109635ad68a929fcbb8964dc965b76cb5ee013" +"checksum slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5f9776d6b986f77b35c6cf846c11ad986ff128fe0b2b63a3628e3755e8d3102d" "checksum socket2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ff606e0486e88f5fc6cfeb3966e434fb409abbc7a3ab495238f70a1ca97f789d" +"checksum string 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "00caf261d6f90f588f8450b8e1230fa0d5be49ee6140fdfbcb55335aff350970" "checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" -"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)" = "90d5efaad92a0f96c629ae16302cc9591915930fd49ff0dcc6b4cde146782397" -"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -"checksum synstructure 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a761d12e6d8dcb4dcf952a7a89b475e3a9d69e4a69307e01a470977642914bd" +"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" +"checksum synstructure 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "85bb9b7550d063ea184027c9b8c20ac167cd36d3e06b3a40bceb9d746dc1a7b7" "checksum tabwriter 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "56ab9ac71e2a71d113e4568ab0a89e2182f0fc214d2e4952c6e5655cb8eac4dd" -"checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 3.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b103c6d08d323b92ff42c8ce62abcd83ca8efa7fd5bf7927efefec75f58c76" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" @@ -2179,29 +2162,29 @@ dependencies = [ "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" "checksum thread_local 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "279ef31c19ededf577bfd12dfae728040a21f635b06a24cd670ff510edd38963" "checksum time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "a15375f1df02096fb3317256ce2cee6a1f42fc84ea5ad5fc8c421cfe40c73098" -"checksum tokio 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "be15ef40f675c9fe66e354d74c73f3ed012ca1aa14d65846a33ee48f1ae8d922" -"checksum tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "aeeffbbb94209023feaef3c196a41cbcdafa06b4a6f893f68779bb5e53796f71" -"checksum tokio-executor 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8cac2a7883ff3567e9d66bb09100d09b33d90311feca0206c7ca034bc0c55113" -"checksum tokio-io 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af9eb326f64b2d6b68438e1953341e00ab3cf54de7e35d92bfc73af8555313a" -"checksum tokio-proto 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fbb47ae81353c63c487030659494b295f6cb6576242f907f203473b191b0389" +"checksum tokio 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "6e93c78d23cc61aa245a8acd2c4a79c4d7fa7fb5c3ca90d5737029f043a84895" +"checksum tokio-codec 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "881e9645b81c2ce95fcb799ded2c29ffb9f25ef5bef909089a420e5961dd8ccb" +"checksum tokio-current-thread 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f90fcd90952f0a496d438a976afba8e5c205fb12123f813d8ab3aa1c8436638c" +"checksum tokio-executor 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c117b6cf86bb730aab4834f10df96e4dd586eff2c3c27d3781348da49e255bde" +"checksum tokio-fs 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b5cbe4ca6e71cb0b62a66e4e6f53a8c06a6eefe46cc5f665ad6f274c9906f135" +"checksum tokio-io 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6cc2de7725863c86ac71b0b9068476fec50834f055a243558ef1655bbd34cb" "checksum tokio-reactor 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b3cedc8e5af5131dc3423ffa4f877cce78ad25259a9a62de0613735a13ebc64b" -"checksum tokio-service 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24da22d077e0f15f55162bdbdc661228c1581892f52074fb242678d015b45162" -"checksum tokio-signal 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e8f46863230f9a05cf52d173721ec391b9c5782a2465f593029922b8782b9ffe" +"checksum tokio-signal 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b6893092932264944edee8486d54b578c7098bea794aedaf9bd7947b49e6b7bf" "checksum tokio-tcp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec9b094851aadd2caf83ba3ad8e8c4ce65a42104f7b94d9e6550023f0407853f" -"checksum tokio-threadpool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3d05cdd6a78005e535d2b27c21521bdf91fbb321027a62d8e178929d18966d" -"checksum tokio-timer 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6131e780037787ff1b3f8aad9da83bca02438b72277850dd6ad0d455e0e20efc" -"checksum tokio-timer 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535fed0ccee189f3d48447587697ba3fd234b3dbbb091f0ec4613ddfec0a7c4c" -"checksum tokio-tls 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "772f4b04e560117fe3b0a53e490c16ddc8ba6ec437015d91fa385564996ed913" +"checksum tokio-threadpool 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a5758cecb6e0633cea5d563ac07c975e04961690b946b04fd84e7d6445a8f6af" +"checksum tokio-timer 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d03fa701f9578a01b7014f106b47f0a363b4727a7f3f75d666e312ab7acbbf1c" +"checksum tokio-tls 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e53fdbf3156f588be1676022fe794232b24922d426e8c14f4e46891c1e31c440" "checksum tokio-udp 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "137bda266504893ac4774e0ec4c2108f7ccdbcb7ac8dced6305fe9e4e0b5041a" -"checksum tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "65ae5d255ce739e8537221ed2942e0445f4b3b813daebac1c0050ddaaa3587f9" +"checksum tokio-uds 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "22e3aa6d1fcc19e635418dc0a30ab5bd65d347973d6f43f1a37bf8d9d1335fc9" "checksum toml 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a0263c6c02c4db6c8f7681f9fd35e90de799ebd4cfdeab77a38f4ff6b3d8c0d9" +"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" +"checksum typed-headers 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fb9c89066fda8824c7c9570d0f5c0dddd2a0b272b189855f89450e830f196eb" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum unicase 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284b6d3db520d67fbe88fd778c21510d1b0ba4a551e5d0fbb023d33405f6de8a" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "51ccda9ef9efa3f7ef5d91e8f9b83bbe6955f9bf86aec89d5cce2c874625920f" "checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" "checksum url 1.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f808aadd8cfec6ef90e4a14eb46f24511824d1ac596b9682703c87056c8678b7" @@ -2213,6 +2196,7 @@ dependencies = [ "checksum version-compare 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "78068add8bf1e4d37d13fa5867182fe4c03f8e525c831053733f83aaba942d37" "checksum version_check 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6b772017e347561807c1aa192438c5fd74242a670a6cffacc40f2defd1dc069d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" +"checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" "checksum widestring 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a212922ea58fbf5044f83663aa4fc6281ff890f1fd7546c0c3f52f5290831781" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "773ef9dcc5f24b7d850d0ff101e542ff24c3b090a9768e03ff889fdef41f00fd" diff --git a/edgelet/build/linux/build.sh b/edgelet/build/linux/build.sh index 96efb5d93a6..53cd678e302 100755 --- a/edgelet/build/linux/build.sh +++ b/edgelet/build/linux/build.sh @@ -60,6 +60,24 @@ process_args() process_args "$@" +# ld crashes in the VSTS CI's Linux amd64 job while trying to link iotedged +# with a generic exit code 1 and no indicative error message. It seems to +# work fine if we reduce the number of objects given to the linker, +# by disabling parallel codegen and incremental compile. +# +# We don't want to disable these for everyone else, so only do it in this script +# that the CI uses. +>> "$PROJECT_ROOT/Cargo.toml" cat <<-EOF + +[profile.dev] +codegen-units = 1 +incremental = false + +[profile.test] +codegen-units = 1 +incremental = false +EOF + if [[ -z ${RELEASE} ]]; then cd "$PROJECT_ROOT" && $CARGO "+$TOOLCHAIN" build --all else diff --git a/edgelet/build/linux/clippy.sh b/edgelet/build/linux/clippy.sh index 5da2b0ad590..f20fb72d217 100755 --- a/edgelet/build/linux/clippy.sh +++ b/edgelet/build/linux/clippy.sh @@ -16,8 +16,7 @@ DIR=$(cd "$(dirname "$0")" && pwd) BUILD_REPOSITORY_LOCALPATH=${BUILD_REPOSITORY_LOCALPATH:-$DIR/../../..} PROJECT_ROOT=${BUILD_REPOSITORY_LOCALPATH}/edgelet SCRIPT_NAME=$(basename "$0") -IMAGE="azureiotedge/cargo-clippy:nightly" -USE_DOCKER=1 +TOOLCHAIN='nightly-2018-09-12' RUSTUP="$HOME/.cargo/bin/rustup" CARGO="$HOME/.cargo/bin/cargo" @@ -30,8 +29,6 @@ function usage() echo "" echo "options" echo " -h, --help Print this help and exit." - echo " -i, --image Docker image to run (default: $IMAGE)" - echo " -d, --use-docker Run clippy using a docker image (default: Do not run in a docker image)" exit 1; } @@ -44,14 +41,9 @@ function print_help_and_exit() function run_clippy() { echo "Running clippy..." - (cd $PROJECT_ROOT && $CARGO +nightly clippy --all) + (cd $PROJECT_ROOT && $CARGO "+$TOOLCHAIN" clippy --all) } -function run_clippy_via_docker() -{ - echo "Running clippy docker image..." - docker run --user "$(id -u)":"$(id -g)" --rm -v "$PROJECT_ROOT:/volume" "$IMAGE" -} ############################################################################### # Obtain and validate the options supported by this script ############################################################################### @@ -61,14 +53,10 @@ function process_args() for arg in "$@" do if [ $save_next_arg -eq 1 ]; then - IMAGE="$arg" - USE_DOCKER=1 save_next_arg=0 else case "$arg" in "-h" | "--help" ) usage;; - "-i" | "--image" ) save_next_arg=1;; - "-d" | "--use-docker" ) USE_DOCKER=1;; * ) usage;; esac fi @@ -80,9 +68,9 @@ process_args "$@" if [[ $USE_DOCKER -eq 1 ]]; then run_clippy_via_docker else - echo "Installing nightly toolchain" - $RUSTUP install nightly + echo "Installing $TOOLCHAIN toolchain" + $RUSTUP install "$TOOLCHAIN" echo "Installing clippy..." - $RUSTUP component add clippy-preview --toolchain=nightly + $RUSTUP component add clippy-preview "--toolchain=$TOOLCHAIN" run_clippy fi diff --git a/edgelet/doc/devguide.md b/edgelet/doc/devguide.md index 97ff34c2833..1f3b368c70b 100644 --- a/edgelet/doc/devguide.md +++ b/edgelet/doc/devguide.md @@ -29,6 +29,28 @@ sudo apt-get update sudo apt-get install -y git cmake build-essential curl libcurl4-openssl-dev libssl-dev uuid-dev pkg-config ``` +#### Windows + +1. Install `vcpkg` + + ```powershell + git clone https://github.com/Microsoft/vcpkg + cd vcpkg + .\bootstrap-vcpkg.bat + ``` + +1. Install openssl binaries + + ```powershell + vcpkg install openssl:x64-windows + ``` + +1. Set `OPENSSL_ROOT_DIR` + + ```powershell + $env:OPENSSL_ROOT_DIR = "$PWD\installed\x64-windows" + ``` + ### Cargo Cargo is the build tool for rust. You will use cargo frequently. It manages the build of the project, downloading dependencies, testing, etc. You can read more about cargo and it's capabilities in the [cargo book](https://doc.rust-lang.org/cargo/). diff --git a/edgelet/docker-rs/Cargo.toml b/edgelet/docker-rs/Cargo.toml index a3669c9449e..ae000a9c14e 100644 --- a/edgelet/docker-rs/Cargo.toml +++ b/edgelet/docker-rs/Cargo.toml @@ -8,12 +8,10 @@ publish = false base64 = "0.9" failure = "0.1" futures = "0.1" -hyper = "0.11" +hyper = "0.12" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" serde_yaml = "0.7" +typed-headers = "0.1" url = "1.5" - -[dev-dependencies] -tokio-core = "*" diff --git a/edgelet/docker-rs/src/apis/client.rs b/edgelet/docker-rs/src/apis/client.rs index d68251e9f31..ac08e3c3fd3 100644 --- a/edgelet/docker-rs/src/apis/client.rs +++ b/edgelet/docker-rs/src/apis/client.rs @@ -1,12 +1,12 @@ // Copyright (c) Microsoft. All rights reserved. -use std::rc::Rc; +use std::sync::Arc; use super::configuration::Configuration; use hyper; -pub struct APIClient { - configuration: Rc>, +pub struct APIClient { + configuration: Arc>, container_api: Box<::apis::ContainerApi>, image_api: Box<::apis::ImageApi>, network_api: Box<::apis::NetworkApi>, @@ -14,17 +14,17 @@ pub struct APIClient { volume_api: Box<::apis::VolumeApi>, } -impl APIClient { +impl APIClient { pub fn new(configuration: Configuration) -> APIClient { - let rc = Rc::new(configuration); + let configuration = Arc::new(configuration); APIClient { - configuration: rc.clone(), - container_api: Box::new(::apis::ContainerApiClient::new(rc.clone())), - image_api: Box::new(::apis::ImageApiClient::new(rc.clone())), - network_api: Box::new(::apis::NetworkApiClient::new(rc.clone())), - system_api: Box::new(::apis::SystemApiClient::new(rc.clone())), - volume_api: Box::new(::apis::VolumeApiClient::new(rc.clone())), + configuration: configuration.clone(), + container_api: Box::new(::apis::ContainerApiClient::new(configuration.clone())), + image_api: Box::new(::apis::ImageApiClient::new(configuration.clone())), + network_api: Box::new(::apis::NetworkApiClient::new(configuration.clone())), + system_api: Box::new(::apis::SystemApiClient::new(configuration.clone())), + volume_api: Box::new(::apis::VolumeApiClient::new(configuration.clone())), } } diff --git a/edgelet/docker-rs/src/apis/configuration.rs b/edgelet/docker-rs/src/apis/configuration.rs index b874b56e8bc..f881faf441e 100644 --- a/edgelet/docker-rs/src/apis/configuration.rs +++ b/edgelet/docker-rs/src/apis/configuration.rs @@ -10,14 +10,14 @@ use failure::err_msg; use failure::Error; -use hyper::client::Connect; +use hyper::client::connect::Connect; use hyper::{Client, Uri}; pub struct Configuration { pub base_path: String, pub user_agent: Option, pub client: Client, - pub uri_composer: Box Result>, + pub uri_composer: Box Result + Send + Sync>, } impl Configuration { diff --git a/edgelet/docker-rs/src/apis/container_api.rs b/edgelet/docker-rs/src/apis/container_api.rs index ff9e91e3df3..3f00b3b64a5 100644 --- a/edgelet/docker-rs/src/apis/container_api.rs +++ b/edgelet/docker-rs/src/apis/container_api.rs @@ -10,30 +10,30 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; +use typed_headers::{self, http, mime, HeaderMapExt}; -use hyper::header::UserAgent; - +use super::super::utils::UserAgent; use super::{configuration, Error}; -pub struct ContainerApiClient { - configuration: Rc>, +pub struct ContainerApiClient { + configuration: Arc>, } -impl ContainerApiClient { - pub fn new(configuration: Rc>) -> ContainerApiClient { +impl ContainerApiClient { + pub fn new(configuration: Arc>) -> ContainerApiClient { ContainerApiClient { configuration: configuration, } } } -pub trait ContainerApi { +pub trait ContainerApi: Send + Sync { fn container_archive( &self, id: &str, @@ -72,14 +72,14 @@ pub trait ContainerApi { &self, body: ::models::ContainerCreateBody, name: &str, - ) -> Box>>; + ) -> Box> + Send>; fn container_delete( &self, id: &str, v: bool, force: bool, link: bool, - ) -> Box>>; + ) -> Box> + Send>; fn container_export( &self, id: &str, @@ -88,7 +88,7 @@ pub trait ContainerApi { &self, id: &str, size: bool, - ) -> Box>>; + ) -> Box> + Send>; fn container_kill( &self, id: &str, @@ -100,7 +100,7 @@ pub trait ContainerApi { limit: i32, size: bool, filters: &str, - ) -> Box, Error = Error>>; + ) -> Box, Error = Error> + Send>; fn container_logs( &self, id: &str, @@ -110,7 +110,7 @@ pub trait ContainerApi { since: i32, timestamps: bool, tail: &str, - ) -> Box>>; + ) -> Box> + Send>; fn container_pause(&self, id: &str) -> Box>>; fn container_prune( @@ -132,12 +132,12 @@ pub trait ContainerApi { &self, id: &str, t: i32, - ) -> Box>>; + ) -> Box> + Send>; fn container_start( &self, id: &str, detach_keys: &str, - ) -> Box>>; + ) -> Box> + Send>; fn container_stats( &self, id: &str, @@ -147,7 +147,7 @@ pub trait ContainerApi { &self, id: &str, t: i32, - ) -> Box>>; + ) -> Box> + Send>; fn container_top( &self, id: &str, @@ -176,7 +176,12 @@ pub trait ContainerApi { ) -> Box>>; } -impl ContainerApi for ContainerApiClient { +impl ContainerApi for ContainerApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn container_archive( &self, id: &str, @@ -184,7 +189,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("path", &path.to_string()) @@ -196,12 +201,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -210,9 +217,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -232,7 +238,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Head; + let method = hyper::Method::HEAD; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("path", &path.to_string()) @@ -244,12 +250,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -258,9 +266,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -285,7 +292,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("detachKeys", &detach_keys.to_string()) @@ -302,12 +309,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -316,9 +325,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -343,7 +351,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("detachKeys", &detach_keys.to_string()) @@ -360,12 +368,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -374,9 +384,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -396,7 +405,7 @@ impl ContainerApi for ContainerApiClient { { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/containers/{id}/changes", id = id); @@ -405,12 +414,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -419,9 +430,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -442,10 +452,11 @@ impl ContainerApi for ContainerApiClient { &self, body: ::models::ContainerCreateBody, name: &str, - ) -> Box>> { + ) -> Box> + Send> + { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("name", &name.to_string()) @@ -457,18 +468,21 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&body).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&body).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -477,9 +491,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -502,10 +515,10 @@ impl ContainerApi for ContainerApiClient { v: bool, force: bool, link: bool, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Delete; + let method = hyper::Method::DELETE; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("v", &v.to_string()) @@ -519,12 +532,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -533,9 +548,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -554,7 +568,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/containers/{id}/export", id = id); @@ -563,12 +577,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -577,9 +593,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -596,10 +611,11 @@ impl ContainerApi for ContainerApiClient { &self, id: &str, size: bool, - ) -> Box>> { + ) -> Box> + Send> + { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("size", &size.to_string()) @@ -611,12 +627,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -625,9 +643,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -651,7 +668,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("signal", &signal.to_string()) @@ -663,12 +680,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -677,9 +696,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -698,10 +716,11 @@ impl ContainerApi for ContainerApiClient { limit: i32, size: bool, filters: &str, - ) -> Box, Error = Error>> { + ) -> Box, Error = Error> + Send> + { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("all", &all.to_string()) @@ -716,12 +735,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -730,9 +751,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -758,10 +778,10 @@ impl ContainerApi for ContainerApiClient { since: i32, timestamps: bool, tail: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("follow", &follow.to_string()) @@ -778,12 +798,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -792,9 +814,9 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); + let (http::response::Parts { status, .. }, body) = resp.into_parts(); if status.is_success() { - Ok(resp.body()) + Ok(body) } else { let b: &[u8] = &[]; Err(Error::from((status, b))) @@ -809,7 +831,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/containers/{id}/pause", id = id); @@ -818,12 +840,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -832,9 +856,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -853,7 +876,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("filters", &filters.to_string()) @@ -865,12 +888,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -879,9 +904,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -905,7 +929,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("name", &name.to_string()) @@ -917,12 +941,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -931,9 +957,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -954,7 +979,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("h", &h.to_string()) @@ -967,12 +992,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -981,9 +1008,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1000,10 +1026,10 @@ impl ContainerApi for ContainerApiClient { &self, id: &str, t: i32, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("t", &t.to_string()) @@ -1015,12 +1041,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -1029,9 +1057,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1048,10 +1075,10 @@ impl ContainerApi for ContainerApiClient { &self, id: &str, detach_keys: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("detachKeys", &detach_keys.to_string()) @@ -1063,12 +1090,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -1077,9 +1106,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1099,7 +1127,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("stream", &stream.to_string()) @@ -1111,12 +1139,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -1125,9 +1155,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1147,10 +1176,10 @@ impl ContainerApi for ContainerApiClient { &self, id: &str, t: i32, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("t", &t.to_string()) @@ -1162,12 +1191,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -1176,9 +1207,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1198,7 +1228,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("ps_args", &ps_args.to_string()) @@ -1210,12 +1240,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -1224,9 +1256,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1249,7 +1280,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/containers/{id}/unpause", id = id); @@ -1258,12 +1289,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -1272,9 +1305,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1294,7 +1326,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/containers/{id}/update", id = id); @@ -1303,18 +1335,21 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&update).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&update).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -1323,9 +1358,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1349,7 +1383,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("condition", &condition.to_string()) @@ -1361,12 +1395,14 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -1375,9 +1411,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -1403,7 +1438,7 @@ impl ContainerApi for ContainerApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Put; + let method = hyper::Method::PUT; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("path", &path.to_string()) @@ -1418,18 +1453,21 @@ impl ContainerApi for ContainerApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&input_stream).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&input_stream).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -1438,9 +1476,8 @@ impl ContainerApi for ContainerApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { diff --git a/edgelet/docker-rs/src/apis/image_api.rs b/edgelet/docker-rs/src/apis/image_api.rs index 2115441983a..80a9001595d 100644 --- a/edgelet/docker-rs/src/apis/image_api.rs +++ b/edgelet/docker-rs/src/apis/image_api.rs @@ -10,32 +10,32 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; +use typed_headers::{self, http, mime, HeaderMapExt}; -use hyper::header::UserAgent; - +use super::super::utils::UserAgent; use super::{configuration, Error}; use models::ImageDeleteResponseItem; -pub struct ImageApiClient { - configuration: Rc>, +pub struct ImageApiClient { + configuration: Arc>, } -impl ImageApiClient { - pub fn new(configuration: Rc>) -> ImageApiClient { +impl ImageApiClient { + pub fn new(configuration: Arc>) -> ImageApiClient { ImageApiClient { configuration: configuration, } } } -pub trait ImageApi { +pub trait ImageApi: Send + Sync { fn build_prune( &self, ) -> Box>>; @@ -87,7 +87,7 @@ pub trait ImageApi { input_image: &str, x_registry_auth: &str, platform: &str, - ) -> Box>>; + ) -> Box> + Send>; fn image_delete( &self, name: &str, @@ -145,13 +145,18 @@ pub trait ImageApi { ) -> Box>>; } -impl ImageApi for ImageApiClient { +impl ImageApi for ImageApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn build_prune( &self, ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/build/prune"); @@ -160,12 +165,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -174,9 +181,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -223,7 +229,7 @@ impl ImageApi for ImageApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("dockerfile", &dockerfile.to_string()) @@ -256,24 +262,23 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&input_stream).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - { - let headers = req.headers_mut(); - headers.set_raw("Content-type", content_type); - headers.set_raw("X-Registry-Config", x_registry_config); - } - - let serialized = serde_json::to_string(&input_stream).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .header(http::header::CONTENT_TYPE, content_type) + .header("X-Registry-Config", x_registry_config) + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -282,9 +287,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -310,7 +314,7 @@ impl ImageApi for ImageApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("container", &container.to_string()) @@ -328,18 +332,21 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&container_config).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&container_config).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -348,9 +355,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -375,10 +381,10 @@ impl ImageApi for ImageApiClient { input_image: &str, x_registry_auth: &str, platform: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("fromImage", &from_image.to_string()) @@ -394,23 +400,22 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&input_image).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); - } - - { - let headers = req.headers_mut(); - headers.set_raw("X-Registry-Auth", x_registry_auth); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&input_image).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .header("X-Registry-Auth", x_registry_auth) + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -419,9 +424,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -442,7 +446,7 @@ impl ImageApi for ImageApiClient { ) -> Box, Error = Error>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Delete; + let method = hyper::Method::DELETE; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("force", &force.to_string()) @@ -455,12 +459,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -469,9 +475,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -496,7 +501,7 @@ impl ImageApi for ImageApiClient { ) -> Box, Error = Error>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/images/{name}/get", name = name); @@ -505,12 +510,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -519,9 +526,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -543,7 +549,7 @@ impl ImageApi for ImageApiClient { ) -> Box, Error = Error>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("names", &names.join(",").to_string()) @@ -555,12 +561,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -569,9 +577,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -594,7 +601,7 @@ impl ImageApi for ImageApiClient { { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/images/{name}/history", name = name); @@ -603,12 +610,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -617,9 +626,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -642,7 +650,7 @@ impl ImageApi for ImageApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/images/{name}/json", name = name); @@ -651,12 +659,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -665,9 +675,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -691,7 +700,7 @@ impl ImageApi for ImageApiClient { ) -> Box, Error = Error>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("all", &all.to_string()) @@ -705,12 +714,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -719,9 +730,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -745,7 +755,7 @@ impl ImageApi for ImageApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("quiet", &quiet.to_string()) @@ -757,18 +767,21 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&images_tarball).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&images_tarball).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -777,9 +790,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -798,7 +810,7 @@ impl ImageApi for ImageApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("filters", &filters.to_string()) @@ -810,12 +822,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -824,9 +838,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -851,7 +864,7 @@ impl ImageApi for ImageApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("tag", &tag.to_string()) @@ -863,17 +876,15 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); - } - - { - let headers = req.headers_mut(); - headers.set_raw("X-Registry-Auth", x_registry_auth); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .header("X-Registry-Auth", x_registry_auth) + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -882,9 +893,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -906,7 +916,7 @@ impl ImageApi for ImageApiClient { { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("term", &term.to_string()) @@ -920,12 +930,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -934,9 +946,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -961,7 +972,7 @@ impl ImageApi for ImageApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("repo", &repo.to_string()) @@ -974,12 +985,14 @@ impl ImageApi for ImageApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -988,9 +1001,8 @@ impl ImageApi for ImageApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { diff --git a/edgelet/docker-rs/src/apis/network_api.rs b/edgelet/docker-rs/src/apis/network_api.rs index 12850473275..d0bc8735bc3 100644 --- a/edgelet/docker-rs/src/apis/network_api.rs +++ b/edgelet/docker-rs/src/apis/network_api.rs @@ -10,30 +10,30 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; +use typed_headers::{self, http, mime, HeaderMapExt}; -use hyper::header::UserAgent; - +use super::super::utils::UserAgent; use super::{configuration, Error}; -pub struct NetworkApiClient { - configuration: Rc>, +pub struct NetworkApiClient { + configuration: Arc>, } -impl NetworkApiClient { - pub fn new(configuration: Rc>) -> NetworkApiClient { +impl NetworkApiClient { + pub fn new(configuration: Arc>) -> NetworkApiClient { NetworkApiClient { configuration: configuration, } } } -pub trait NetworkApi { +pub trait NetworkApi: Send + Sync { fn network_connect( &self, id: &str, @@ -42,7 +42,7 @@ pub trait NetworkApi { fn network_create( &self, network_config: ::models::NetworkConfig, - ) -> Box>>; + ) -> Box> + Send>; fn network_delete(&self, id: &str) -> Box>>; fn network_disconnect( &self, @@ -58,14 +58,19 @@ pub trait NetworkApi { fn network_list( &self, filters: &str, - ) -> Box, Error = Error>>; + ) -> Box, Error = Error> + Send>; fn network_prune( &self, filters: &str, ) -> Box>>; } -impl NetworkApi for NetworkApiClient { +impl NetworkApi for NetworkApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn network_connect( &self, id: &str, @@ -73,7 +78,7 @@ impl NetworkApi for NetworkApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/networks/{id}/connect", id = id); @@ -82,18 +87,21 @@ impl NetworkApi for NetworkApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&container).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&container).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -102,9 +110,8 @@ impl NetworkApi for NetworkApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -120,10 +127,11 @@ impl NetworkApi for NetworkApiClient { fn network_create( &self, network_config: ::models::NetworkConfig, - ) -> Box>> { + ) -> Box> + Send> + { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/networks/create"); @@ -132,18 +140,21 @@ impl NetworkApi for NetworkApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&network_config).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&network_config).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -152,9 +163,8 @@ impl NetworkApi for NetworkApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -174,7 +184,7 @@ impl NetworkApi for NetworkApiClient { fn network_delete(&self, id: &str) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Delete; + let method = hyper::Method::DELETE; let uri_str = format!("/networks/{id}", id = id); @@ -183,12 +193,14 @@ impl NetworkApi for NetworkApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -197,9 +209,8 @@ impl NetworkApi for NetworkApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -219,7 +230,7 @@ impl NetworkApi for NetworkApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/networks/{id}/disconnect", id = id); @@ -228,18 +239,21 @@ impl NetworkApi for NetworkApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&container).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&container).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -248,9 +262,8 @@ impl NetworkApi for NetworkApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -271,7 +284,7 @@ impl NetworkApi for NetworkApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("verbose", &verbose.to_string()) @@ -284,12 +297,14 @@ impl NetworkApi for NetworkApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -298,9 +313,8 @@ impl NetworkApi for NetworkApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -319,10 +333,10 @@ impl NetworkApi for NetworkApiClient { fn network_list( &self, filters: &str, - ) -> Box, Error = Error>> { + ) -> Box, Error = Error> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("filters", &filters.to_string()) @@ -334,12 +348,14 @@ impl NetworkApi for NetworkApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -348,9 +364,8 @@ impl NetworkApi for NetworkApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -372,7 +387,7 @@ impl NetworkApi for NetworkApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("filters", &filters.to_string()) @@ -384,12 +399,14 @@ impl NetworkApi for NetworkApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -398,9 +415,8 @@ impl NetworkApi for NetworkApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { diff --git a/edgelet/docker-rs/src/apis/system_api.rs b/edgelet/docker-rs/src/apis/system_api.rs index 02cdac9ff83..11422078ef7 100644 --- a/edgelet/docker-rs/src/apis/system_api.rs +++ b/edgelet/docker-rs/src/apis/system_api.rs @@ -10,30 +10,30 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; +use typed_headers::{self, http, mime, HeaderMapExt}; -use hyper::header::UserAgent; - +use super::super::utils::UserAgent; use super::{configuration, Error}; -pub struct SystemApiClient { - configuration: Rc>, +pub struct SystemApiClient { + configuration: Arc>, } -impl SystemApiClient { - pub fn new(configuration: Rc>) -> SystemApiClient { +impl SystemApiClient { + pub fn new(configuration: Arc>) -> SystemApiClient { SystemApiClient { configuration: configuration, } } } -pub trait SystemApi { +pub trait SystemApi: Send + Sync { fn system_auth( &self, auth_config: ::models::AuthConfig, @@ -49,21 +49,26 @@ pub trait SystemApi { ) -> Box>>; fn system_info( &self, - ) -> Box>>; + ) -> Box> + Send>; fn system_ping(&self) -> Box>>; fn system_version( &self, ) -> Box>>; } -impl SystemApi for SystemApiClient { +impl SystemApi for SystemApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn system_auth( &self, auth_config: ::models::AuthConfig, ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/auth"); @@ -72,18 +77,21 @@ impl SystemApi for SystemApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&auth_config).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&auth_config).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -92,9 +100,8 @@ impl SystemApi for SystemApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -116,7 +123,7 @@ impl SystemApi for SystemApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/system/df"); @@ -125,12 +132,14 @@ impl SystemApi for SystemApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -139,9 +148,8 @@ impl SystemApi for SystemApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -166,7 +174,7 @@ impl SystemApi for SystemApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("since", &since.to_string()) @@ -180,12 +188,14 @@ impl SystemApi for SystemApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -194,9 +204,8 @@ impl SystemApi for SystemApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -215,10 +224,10 @@ impl SystemApi for SystemApiClient { fn system_info( &self, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/info"); @@ -227,12 +236,14 @@ impl SystemApi for SystemApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -241,9 +252,8 @@ impl SystemApi for SystemApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -262,7 +272,7 @@ impl SystemApi for SystemApiClient { fn system_ping(&self) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/_ping"); @@ -271,12 +281,14 @@ impl SystemApi for SystemApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -285,9 +297,8 @@ impl SystemApi for SystemApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -308,7 +319,7 @@ impl SystemApi for SystemApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/version"); @@ -317,12 +328,14 @@ impl SystemApi for SystemApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -331,9 +344,8 @@ impl SystemApi for SystemApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { diff --git a/edgelet/docker-rs/src/apis/volume_api.rs b/edgelet/docker-rs/src/apis/volume_api.rs index 8109fadb248..089fb2f742d 100644 --- a/edgelet/docker-rs/src/apis/volume_api.rs +++ b/edgelet/docker-rs/src/apis/volume_api.rs @@ -10,30 +10,30 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; +use typed_headers::{self, http, mime, HeaderMapExt}; -use hyper::header::UserAgent; - +use super::super::utils::UserAgent; use super::{configuration, Error}; -pub struct VolumeApiClient { - configuration: Rc>, +pub struct VolumeApiClient { + configuration: Arc>, } -impl VolumeApiClient { - pub fn new(configuration: Rc>) -> VolumeApiClient { +impl VolumeApiClient { + pub fn new(configuration: Arc>) -> VolumeApiClient { VolumeApiClient { configuration: configuration, } } } -pub trait VolumeApi { +pub trait VolumeApi: Send + Sync { fn volume_create( &self, volume_config: ::models::VolumeConfig, @@ -57,14 +57,19 @@ pub trait VolumeApi { ) -> Box>>; } -impl VolumeApi for VolumeApiClient { +impl VolumeApi for VolumeApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn volume_create( &self, volume_config: ::models::VolumeConfig, ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let uri_str = format!("/volumes/create"); @@ -73,18 +78,21 @@ impl VolumeApi for VolumeApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&volume_config).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&volume_config).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -93,9 +101,8 @@ impl VolumeApi for VolumeApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -118,7 +125,7 @@ impl VolumeApi for VolumeApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Delete; + let method = hyper::Method::DELETE; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("force", &force.to_string()) @@ -130,12 +137,14 @@ impl VolumeApi for VolumeApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -144,9 +153,8 @@ impl VolumeApi for VolumeApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -165,7 +173,7 @@ impl VolumeApi for VolumeApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let uri_str = format!("/volumes/{name}", name = name); @@ -174,12 +182,14 @@ impl VolumeApi for VolumeApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -188,9 +198,8 @@ impl VolumeApi for VolumeApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -212,7 +221,7 @@ impl VolumeApi for VolumeApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("filters", &filters.to_string()) @@ -224,12 +233,14 @@ impl VolumeApi for VolumeApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -238,9 +249,8 @@ impl VolumeApi for VolumeApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { @@ -263,7 +273,7 @@ impl VolumeApi for VolumeApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("filters", &filters.to_string()) @@ -275,12 +285,14 @@ impl VolumeApi for VolumeApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -289,9 +301,8 @@ impl VolumeApi for VolumeApiClient { .request(req) .map_err(|e| Error::from(e)) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(|e| Error::from(e)) }).and_then(|(status, body)| { diff --git a/edgelet/docker-rs/src/lib.rs b/edgelet/docker-rs/src/lib.rs index 778d26ee2e2..28ac6db18f9 100644 --- a/edgelet/docker-rs/src/lib.rs +++ b/edgelet/docker-rs/src/lib.rs @@ -1,11 +1,14 @@ +// Copyright (c) Microsoft. All rights reserved. + +#![deny(unused_extern_crates, warnings)] #![allow( - unused_imports, + dead_code, non_snake_case, + renamed_and_removed_lints, + unused_imports, unused_mut, - dead_code, - unknown_lints )] -#![allow(clippy, clippy_pedantic)] +#![cfg_attr(feature = "cargo-clippy", allow(clippy, clippy_pedantic))] #[macro_use] extern crate serde_derive; @@ -16,6 +19,7 @@ extern crate futures; extern crate hyper; extern crate serde; extern crate serde_json; +extern crate typed_headers; extern crate url; pub mod apis; diff --git a/edgelet/docker-rs/src/utils.rs b/edgelet/docker-rs/src/utils.rs index 003092e6e0f..465836fb0e9 100644 --- a/edgelet/docker-rs/src/utils.rs +++ b/edgelet/docker-rs/src/utils.rs @@ -2,7 +2,9 @@ use serde::Deserialize; use serde_json; +use std::borrow::Cow; use std::str::FromStr; +use typed_headers::{self, http}; use models::ContainerCreateBody; @@ -13,3 +15,37 @@ impl FromStr for ContainerCreateBody { serde_json::from_str(s) } } + +#[derive(Clone, Debug, PartialEq)] +pub(crate) struct UserAgent<'a>(pub Cow<'a, str>); + +impl<'a> typed_headers::Header for UserAgent<'a> { + fn name() -> &'static http::header::HeaderName { + &http::header::USER_AGENT + } + + fn from_values<'b>( + values: &mut http::header::ValueIter<'b, http::header::HeaderValue>, + ) -> Result, typed_headers::Error> + where + Self: Sized, + { + match values.next() { + Some(value) => { + let value = value + .to_str() + .map_err(|_| typed_headers::Error::invalid_value())? + .trim() + .to_string() + .into(); + Ok(Some(UserAgent(value))) + } + + None => Ok(None), + } + } + + fn to_values(&self, values: &mut typed_headers::ToValues) { + typed_headers::util::encode_single_value(&self.0, values); + } +} diff --git a/edgelet/dps/Cargo.toml b/edgelet/dps/Cargo.toml index 48b99b3887d..7e6541bdf67 100644 --- a/edgelet/dps/Cargo.toml +++ b/edgelet/dps/Cargo.toml @@ -9,19 +9,17 @@ bytes = "0.4" chrono = { version = "0.4", features = ["serde"] } failure = "0.1" futures = "0.1" -hyper = "0.11" +hyper = "0.12" log = "0.4" percent-encoding = "1.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" tokio = "0.1" -tokio-timer = "0.1" url = "1.7" edgelet-core = { path = "../edgelet-core" } edgelet-http = { path = "../edgelet-http" } -edgelet-utils = { path = "../edgelet-utils" } -[dev_dependencies] -tokio-core = "0.1" +[dev-dependencies] +http = "0.1" diff --git a/edgelet/dps/src/error.rs b/edgelet/dps/src/error.rs index 5fcb3c132d0..b5bf65b206a 100644 --- a/edgelet/dps/src/error.rs +++ b/edgelet/dps/src/error.rs @@ -6,7 +6,7 @@ use std::fmt::Display; use base64::DecodeError; use failure::{Backtrace, Context, Fail}; use serde_json::Error as SerdeError; -use tokio_timer::TimerError as TokioError; +use tokio::timer::Error as TimerError; use edgelet_core::Error as CoreError; use edgelet_http::{Error as HttpError, ErrorKind as HttpErrorKind}; @@ -106,8 +106,8 @@ impl From for HttpError { } } -impl From for Error { - fn from(error: TokioError) -> Error { +impl From for Error { + fn from(error: TimerError) -> Error { Error { inner: error.context(ErrorKind::TimerError), } diff --git a/edgelet/dps/src/lib.rs b/edgelet/dps/src/lib.rs index 5f1af8f665b..8b593c2be18 100644 --- a/edgelet/dps/src/lib.rs +++ b/edgelet/dps/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] extern crate base64; extern crate bytes; @@ -8,24 +8,21 @@ extern crate chrono; #[macro_use] extern crate failure; extern crate futures; +#[cfg(test)] +extern crate http; extern crate hyper; #[macro_use] extern crate log; #[macro_use] extern crate percent_encoding; -extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; extern crate tokio; -#[cfg(test)] -extern crate tokio_core; -extern crate tokio_timer; extern crate url; extern crate edgelet_core; extern crate edgelet_http; -extern crate edgelet_utils; pub mod error; mod model; diff --git a/edgelet/dps/src/registration.rs b/edgelet/dps/src/registration.rs index 267febe5f2c..902d4c59a39 100644 --- a/edgelet/dps/src/registration.rs +++ b/edgelet/dps/src/registration.rs @@ -8,8 +8,7 @@ use bytes::Bytes; use chrono::{DateTime, Utc}; use futures::future::Either; use futures::{future, Future}; -use hyper::client::Service; -use hyper::{Error as HyperError, Method, Request, Response, StatusCode}; +use hyper::{Method, StatusCode}; use percent_encoding::{percent_encode, PATH_SEGMENT_ENCODE_SET}; use serde_json; use tokio::prelude::*; @@ -17,7 +16,7 @@ use tokio::timer::Interval; use url::form_urlencoded::Serializer as UrlSerializer; use edgelet_core::crypto::{Activate, KeyIdentity, KeyStore, Sign, Signature, SignatureAlgorithm}; -use edgelet_http::client::{Client, TokenSource}; +use edgelet_http::client::{Client, ClientImpl, TokenSource}; use edgelet_http::ErrorKind as HttpErrorKind; use error::{Error, ErrorKind}; use model::{ @@ -87,13 +86,13 @@ where } } -pub struct DpsClient +pub struct DpsClient where - S: 'static + Service, + C: ClientImpl, K: 'static + Sign + Clone, A: 'static + KeyStore + Activate + Clone, { - client: Arc>>>, + client: Arc>>>, scope_id: String, registration_id: String, tpm_ek: Bytes, @@ -101,20 +100,20 @@ where key_store: A, } -impl DpsClient +impl DpsClient where - S: 'static + Service, - K: 'static + Sign + Clone, - A: 'static + KeyStore + Activate + Clone, + C: 'static + ClientImpl, + K: 'static + Sign + Clone + Send + Sync, + A: 'static + KeyStore + Activate + Clone + Send, { pub fn new( - client: Client>, + client: Client>, scope_id: String, registration_id: String, tpm_ek: Bytes, tpm_srk: Bytes, key_store: A, - ) -> Result, Error> { + ) -> Result { Ok(DpsClient { client: Arc::new(RwLock::new(client)), scope_id, @@ -150,12 +149,12 @@ where } fn get_operation_id( - client: &Arc>>>, + client: &Arc>>>, scope_id: &str, registration_id: &str, registration: &DeviceRegistration, key: K, - ) -> Box, Error = Error>> { + ) -> Box, Error = Error> + Send> { let token_source = DpsTokenSource::new(scope_id.to_string(), registration_id.to_string(), key); debug!( @@ -168,7 +167,7 @@ where .clone() .with_token_source(token_source) .request::( - Method::Put, + Method::PUT, &format!("{}/registrations/{}/register", scope_id, registration_id), None, Some(registration.clone()), @@ -178,19 +177,19 @@ where } fn get_operation_status( - client: &Arc>>>, + client: &Arc>>>, scope_id: &str, registration_id: &str, operation_id: &str, key: K, - ) -> Box, Error = Error>> { + ) -> Box, Error = Error> + Send> { let token_source = DpsTokenSource::new(scope_id.to_string(), registration_id.to_string(), key); let request = client.read().expect("RwLock read failure") .clone() .with_token_source(token_source) .request::<(), RegistrationOperationStatus>( - Method::Get, + Method::GET, &format!( "{}/registrations/{}/operations/{}", scope_id, registration_id, operation_id @@ -245,13 +244,13 @@ where // skip_while and take(1) implement discarding all but the desired result. Finally fold is // called on the desired result to format and return it from the function. fn get_device_registration_result( - client: Arc>>>, + client: Arc>>>, scope_id: String, registration_id: String, operation_id: String, key: K, retry_count: u64, - ) -> Box, Error = Error>> { + ) -> Box, Error = Error> + Send> { debug!( "DPS registration result will retry {} times every {} seconds", retry_count, DPS_ASSIGNMENT_RETRY_INTERVAL_SECS @@ -283,13 +282,13 @@ where } fn register_with_auth( - client: &Arc>>>, + client: &Arc>>>, scope_id: String, registration_id: String, tpm_ek: &Bytes, tpm_srk: &Bytes, key_store: &A, - ) -> Box, Error = Error>> { + ) -> Box, Error = Error> + Send> { let tpm_attestation = TpmAttestation::new(base64::encode(&tpm_ek)) .with_storage_root_key(base64::encode(&tpm_srk)); let registration = DeviceRegistration::new() @@ -301,7 +300,7 @@ where .read() .expect("RwLock read failure") .request::( - Method::Put, + Method::PUT, &format!("{}/registrations/{}/register", scope_id, registration_id), None, Some(registration.clone()), @@ -313,22 +312,23 @@ where // If request is returned with status unauthorized, extract the tpm // challenge from the payload, generate a signature and re-issue the // request - let body = - if let HttpErrorKind::ServiceError(status, ref body) = *err.kind() { - if status == StatusCode::Unauthorized { + let body = match *err.kind() { + HttpErrorKind::ServiceError(status, ref body) => + if status == StatusCode::UNAUTHORIZED { debug!( - "Registration unauthorized, checking response for challenge {}", - status - ); + "Registration unauthorized, checking response for challenge {}", + status, + ); Some(body.clone()) } else { debug!("Unexpected registration status, {}", status); None - } - } else { + }, + _ => { debug!("Response error {:?}", err); None - }; + }, + }; body.map(move |body| { Self::get_tpm_challenge_key(body.as_str(), &mut key_store_inner) @@ -348,7 +348,7 @@ where Box::new(r) } - pub fn register(&self) -> Box> { + pub fn register(&self) -> Box + Send> { let key_store = self.key_store.clone(); let mut key_store_status = self.key_store.clone(); let client_with_token_status = self.client.clone(); @@ -442,52 +442,56 @@ fn get_device_info( mod tests { use super::*; - use std::cell::RefCell; use std::mem; + use std::sync::Mutex; - use hyper::header::Authorization; - use hyper::server::service_fn; - use hyper::StatusCode; + use http; + use hyper::{self, Body, Request, Response, StatusCode}; use serde_json; - use tokio_core::reactor::Core; + use tokio; use url::Url; use edgelet_core::crypto::{MemoryKey, MemoryKeyStore}; #[test] fn server_register_with_auth_success() { - let mut core = Core::new().unwrap(); let expected_uri = "https://global.azure-devices-provisioning.net/scope/registrations/reg/register?api-version=2017-11-15"; - let handler = move |req: Request| { - let (method, uri, _httpversion, headers, _body) = req.deconstruct(); + let handler = move |req: Request| { + let ( + http::request::Parts { + method, + uri, + headers, + .. + }, + _body, + ) = req.into_parts(); assert_eq!(uri, expected_uri); - assert_eq!(method, Method::Put); + assert_eq!(method, Method::PUT); // If authorization header does not have the shared access signature, request one - let auth = headers.get::>(); + let auth = headers.get(hyper::header::AUTHORIZATION); match auth { None => { let mut result = TpmRegistrationResult::new(); result.set_authentication_key(base64::encode("key")); - future::ok( - Response::new() - .with_status(StatusCode::Unauthorized) - .with_body(serde_json::to_string(&result).unwrap().into_bytes()), - ) + let response = Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body(serde_json::to_string(&result).unwrap().into()) + .expect("could not build hyper::Response"); + future::ok(response) } Some(_) => { let mut result = RegistrationOperationStatus::new("something".to_string()) .with_status("assigning".to_string()); - future::ok( - Response::new() - .with_status(StatusCode::Ok) - .with_body(serde_json::to_string(&result).unwrap().into_bytes()), - ) + future::ok(Response::new( + serde_json::to_string(&result).unwrap().into(), + )) } } }; let client = Arc::new(RwLock::new( Client::new( - service_fn(handler), + handler, None, "2017-11-15", Url::parse("https://global.azure-devices-provisioning.net/").unwrap(), @@ -508,15 +512,23 @@ mod tests { } None => panic!("Unexpected"), }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn server_register_gets_404_fails() { - let mut core = Core::new().unwrap(); - let handler = |_req: Request| future::ok(Response::new().with_status(StatusCode::NotFound)); + let handler = |_req: Request| { + let response = Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .expect("could not build hyper::Response"); + future::ok(response) + }; let client = Client::new( - service_fn(handler), + handler, None, "2017-11-15", Url::parse("https://global.azure-devices-provisioning.net/").unwrap(), @@ -540,30 +552,38 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn server_register_with_auth_gets_404_fails() { - let mut core = Core::new().unwrap(); - let handler = |req: Request| { + let handler = |req: Request| { // If authorization header does not have the shared access signature, request one - let auth = req.headers().get::>(); + let auth = req.headers().get(hyper::header::AUTHORIZATION); match auth { None => { let mut result = TpmRegistrationResult::new(); result.set_authentication_key("key".to_string()); - future::ok( - Response::new() - .with_status(StatusCode::Unauthorized) - .with_body(serde_json::to_string(&result).unwrap().into_bytes()), - ) + let response = Response::builder() + .status(StatusCode::UNAUTHORIZED) + .body(serde_json::to_string(&result).unwrap().into()) + .expect("could not build hyper::Response"); + future::ok(response) + } + Some(_) => { + let response = Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .expect("could not build hyper::Response"); + future::ok(response) } - Some(_) => future::ok(Response::new().with_status(StatusCode::NotFound)), } }; let client = Client::new( - service_fn(handler), + handler, None, "2017-11-15", Url::parse("https://global.azure-devices-provisioning.net/").unwrap(), @@ -587,42 +607,45 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn get_device_registration_result_success() { - let mut core = Core::new().unwrap(); - let reg_op_status_vanilla = Response::new().with_status(StatusCode::Ok).with_body( + let reg_op_status_vanilla = Response::new( serde_json::to_string(&RegistrationOperationStatus::new("operation".to_string())) .unwrap() - .into_bytes(), + .into(), ); - let reg_op_status_final = Response::new().with_status(StatusCode::Ok).with_body( + + let reg_op_status_final = Response::new( serde_json::to_string( &RegistrationOperationStatus::new("operation".to_string()).with_registration_state( DeviceRegistrationResult::new("reg".to_string(), "doesn't matter".to_string()), ), ).unwrap() - .into_bytes(), + .into(), ); - let stream = RefCell::new(stream::iter_result(vec![ + + let stream = Mutex::new(stream::iter_result(vec![ Ok(reg_op_status_vanilla), Ok(reg_op_status_final), Err(Error::from(ErrorKind::Unexpected)), ])); - let handler = move |_req: Request| { - if let Async::Ready(opt) = stream.borrow_mut().poll().unwrap() { + let handler = move |_req: Request| { + if let Async::Ready(opt) = stream.lock().unwrap().poll().unwrap() { future::ok(opt.unwrap()) } else { unimplemented!(); } }; let key = MemoryKey::new("key".to_string()); - let service = service_fn(handler); let client = Arc::new(RwLock::new( Client::new( - service, + handler, None, "2017-11-15", Url::parse("https://global.azure-devices-provisioning.net/").unwrap(), @@ -648,27 +671,25 @@ mod tests { } () }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn get_device_registration_result_on_all_attempts_returns_none() { - let mut core = Core::new().unwrap(); - let handler = |_req: Request| { - future::ok( - Response::new().with_status(StatusCode::Ok).with_body( - serde_json::to_string(&RegistrationOperationStatus::new( - "operation".to_string(), - )).unwrap() - .into_bytes(), - ), - ) + let handler = |_req: Request| { + future::ok(Response::new( + serde_json::to_string(&RegistrationOperationStatus::new("operation".to_string())) + .unwrap() + .into(), + )) }; let key = MemoryKey::new("key".to_string()); - let service = service_fn(handler); let client = Arc::new(RwLock::new( Client::new( - service, + handler, None, "2017-11-15", Url::parse("https://global.azure-devices-provisioning.net/").unwrap(), @@ -695,31 +716,31 @@ mod tests { () }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn get_operation_status_success() { - let mut core = Core::new().unwrap(); let expected_uri = "https://global.azure-devices-provisioning.net/scope_id/registrations/reg/operations/operation?api-version=2017-11-15"; - let handler = move |req: Request| { - let (method, uri, _httpversion, _headers, _body) = req.deconstruct(); + let handler = move |req: Request| { + let (http::request::Parts { method, uri, .. }, _body) = req.into_parts(); assert_eq!(uri, expected_uri); - assert_eq!(method, Method::Get); + assert_eq!(method, Method::GET); let operation_status: RegistrationOperationStatus = RegistrationOperationStatus::new("operation".to_string()); let serializable = operation_status.with_registration_state( DeviceRegistrationResult::new("reg".to_string(), "doesn't matter".to_string()), ); - future::ok( - Response::new() - .with_status(StatusCode::Ok) - .with_body(serde_json::to_string(&serializable).unwrap().into_bytes()), - ) + future::ok(Response::new( + serde_json::to_string(&serializable).unwrap().into(), + )) }; let client = Client::new( - service_fn(handler), + handler, None, "2017-11-15", Url::parse("https://global.azure-devices-provisioning.net/").unwrap(), @@ -738,15 +759,24 @@ mod tests { } None => panic!("Unexpected"), }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn get_operation_status_gets_404_fails() { - let mut core = Core::new().unwrap(); - let handler = |_req: Request| future::ok(Response::new().with_status(StatusCode::NotFound)); + let handler = |_req: Request| { + let response = Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .expect("could not build hyper::Response"); + future::ok(response) + }; + let client = Client::new( - service_fn(handler), + handler, None, "2017-11-15", Url::parse("https://global.azure-devices-provisioning.net/").unwrap(), @@ -769,7 +799,10 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] diff --git a/edgelet/edgelet-core/Cargo.toml b/edgelet/edgelet-core/Cargo.toml index 58e58e912b0..c85a57ed5bc 100644 --- a/edgelet/edgelet-core/Cargo.toml +++ b/edgelet/edgelet-core/Cargo.toml @@ -12,7 +12,6 @@ futures = "0.1" failure = "0.1" hmac = "0.5.0" lazy_static = "1.0" -regex = "0.2" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" @@ -20,7 +19,6 @@ sha2 = "0.7.0" log = "0.4" url = "1.7" tokio = "0.1" -tokio-timer = "0.2.3" edgelet-utils = { path = "../edgelet-utils" } diff --git a/edgelet/edgelet-core/src/authorization.rs b/edgelet/edgelet-core/src/authorization.rs index 7ae1c77aa37..0a05bb19b73 100644 --- a/edgelet/edgelet-core/src/authorization.rs +++ b/edgelet/edgelet-core/src/authorization.rs @@ -92,7 +92,6 @@ where #[cfg(test)] mod tests { - use std::time::Duration; use super::*; diff --git a/edgelet/edgelet-core/src/error.rs b/edgelet/edgelet-core/src/error.rs index 7bc38d526c3..6f7f891b663 100644 --- a/edgelet/edgelet-core/src/error.rs +++ b/edgelet/edgelet-core/src/error.rs @@ -6,7 +6,7 @@ use std::num::ParseIntError; use edgelet_utils::Error as UtilsError; use failure::{Backtrace, Context, Fail}; -use tokio_timer; +use tokio; pub type Result = ::std::result::Result; @@ -100,8 +100,8 @@ impl From for Error { } } -impl From for Error { - fn from(error: tokio_timer::Error) -> Error { +impl From for Error { + fn from(error: tokio::timer::Error) -> Error { Error { inner: error.context(ErrorKind::TokioTimer), } diff --git a/edgelet/edgelet-core/src/identity.rs b/edgelet/edgelet-core/src/identity.rs index b96e097b981..762facd0ce5 100644 --- a/edgelet/edgelet-core/src/identity.rs +++ b/edgelet/edgelet-core/src/identity.rs @@ -71,11 +71,11 @@ impl IdentitySpec { pub trait IdentityManager { type Identity: Identity; type Error: Fail; - type CreateFuture: Future; - type UpdateFuture: Future; - type ListFuture: Future, Error = Self::Error>; - type GetFuture: Future, Error = Self::Error>; - type DeleteFuture: Future; + type CreateFuture: Future + Send; + type UpdateFuture: Future + Send; + type ListFuture: Future, Error = Self::Error> + Send; + type GetFuture: Future, Error = Self::Error> + Send; + type DeleteFuture: Future + Send; fn create(&mut self, id: IdentitySpec) -> Self::CreateFuture; fn update(&mut self, id: IdentitySpec) -> Self::UpdateFuture; diff --git a/edgelet/edgelet-core/src/lib.rs b/edgelet/edgelet-core/src/lib.rs index 6de9a427605..cbdaca2e1b9 100644 --- a/edgelet/edgelet-core/src/lib.rs +++ b/edgelet/edgelet-core/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] #[cfg(test)] extern crate base64; @@ -15,14 +15,11 @@ extern crate hmac; extern crate lazy_static; #[macro_use] extern crate log; -extern crate regex; -extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; extern crate sha2; extern crate tokio; -extern crate tokio_timer; #[macro_use] extern crate edgelet_utils; diff --git a/edgelet/edgelet-core/src/module.rs b/edgelet/edgelet-core/src/module.rs index 53c031f9027..8b4e3908c0c 100644 --- a/edgelet/edgelet-core/src/module.rs +++ b/edgelet/edgelet-core/src/module.rs @@ -293,7 +293,7 @@ impl LogOptions { pub trait Module { type Config; type Error: Fail; - type RuntimeStateFuture: Future; + type RuntimeStateFuture: Future + Send; fn name(&self) -> &str; fn type_(&self) -> &str; @@ -303,7 +303,7 @@ pub trait Module { pub trait ModuleRegistry { type Error: Fail; - type PullFuture: Future; + type PullFuture: Future + Send; type RemoveFuture: Future; type Config; @@ -346,22 +346,22 @@ impl SystemInfo { pub trait ModuleRuntime { type Error: Fail; - type Config; - type Module: Module; + type Config: Send; + type Module: Module + Send; type ModuleRegistry: ModuleRegistry; type Chunk: AsRef<[u8]>; - type Logs: Stream; - - type CreateFuture: Future; - type InitFuture: Future; - type ListFuture: Future, Error = Self::Error>; - type LogsFuture: Future; - type RemoveFuture: Future; - type RestartFuture: Future; - type StartFuture: Future; - type StopFuture: Future; - type SystemInfoFuture: Future; - type RemoveAllFuture: Future; + type Logs: Stream + Send; + + type CreateFuture: Future + Send; + type InitFuture: Future + Send; + type ListFuture: Future, Error = Self::Error> + Send; + type LogsFuture: Future + Send; + type RemoveFuture: Future + Send; + type RestartFuture: Future + Send; + type StartFuture: Future + Send; + type StopFuture: Future + Send; + type SystemInfoFuture: Future + Send; + type RemoveAllFuture: Future + Send; fn init(&self) -> Self::InitFuture; fn create(&self, module: ModuleSpec) -> Self::CreateFuture; diff --git a/edgelet/edgelet-docker/Cargo.toml b/edgelet/edgelet-docker/Cargo.toml index c3f81ed9f2b..8d0e3e4e42f 100644 --- a/edgelet/edgelet-docker/Cargo.toml +++ b/edgelet/edgelet-docker/Cargo.toml @@ -9,13 +9,12 @@ base64 = "0.9" chrono = { version = "0.4", features = ["serde"] } failure = "0.1" futures = "0.1" -hyper = "0.11" +hyper = "0.12" lazy_static = "1.0" log = "0.4" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -tokio-core = "0.1" url = "1.7" docker = { path = "../docker-rs" } @@ -24,7 +23,11 @@ edgelet-http = { path = "../edgelet-http" } edgelet-utils = { path = "../edgelet-utils" } [dev_dependencies] -tempfile = "3" time = "0.1" +tokio = "0.1.8" +typed-headers = "0.1" edgelet-test-utils = { path = "../edgelet-test-utils" } + +[target.'cfg(unix)'.dev_dependencies] +tempfile = "3" diff --git a/edgelet/edgelet-docker/src/client.rs b/edgelet/edgelet-docker/src/client.rs index c45f9e1f741..2a4b8fb2473 100644 --- a/edgelet/edgelet-docker/src/client.rs +++ b/edgelet/edgelet-docker/src/client.rs @@ -1,20 +1,20 @@ // Copyright (c) Microsoft. All rights reserved. use std::ops::Deref; -use std::rc::Rc; +use std::sync::Arc; -use hyper::client::Connect; +use hyper::client::connect::Connect; use docker::apis::client::APIClient; pub struct DockerClient { - client: Rc>, + client: Arc>, } impl DockerClient { pub fn new(client: APIClient) -> DockerClient { DockerClient { - client: Rc::new(client), + client: Arc::new(client), } } } diff --git a/edgelet/edgelet-docker/src/error.rs b/edgelet/edgelet-docker/src/error.rs index dd8657fa95c..868f95b279b 100644 --- a/edgelet/edgelet-docker/src/error.rs +++ b/edgelet/edgelet-docker/src/error.rs @@ -127,13 +127,13 @@ impl From> for Error { DockerError::Serde(error) => Error { inner: Error::from(error).context(ErrorKind::Docker), }, - DockerError::ApiError(ref error) if error.code == StatusCode::NotFound => { + DockerError::ApiError(ref error) if error.code == StatusCode::NOT_FOUND => { Error::from(ErrorKind::NotFound) } - DockerError::ApiError(ref error) if error.code == StatusCode::Conflict => { + DockerError::ApiError(ref error) if error.code == StatusCode::CONFLICT => { Error::from(ErrorKind::Conflict) } - DockerError::ApiError(ref error) if error.code == StatusCode::NotModified => { + DockerError::ApiError(ref error) if error.code == StatusCode::NOT_MODIFIED => { Error::from(ErrorKind::NotModified) } _ => Error::from(ErrorKind::DockerRuntime(err)), diff --git a/edgelet/edgelet-docker/src/lib.rs b/edgelet/edgelet-docker/src/lib.rs index 51838f01c78..627d5bdc0b2 100644 --- a/edgelet/edgelet-docker/src/lib.rs +++ b/edgelet/edgelet-docker/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] extern crate base64; extern crate chrono; @@ -13,19 +13,22 @@ extern crate hyper; extern crate lazy_static; #[macro_use] extern crate log; -extern crate serde; #[macro_use] extern crate serde_derive; +#[cfg(test)] +extern crate serde; // Need stuff other than macros from serde_json for non-test code. #[cfg(not(test))] extern crate serde_json; -extern crate tokio_core; +#[cfg(test)] +extern crate tokio; extern crate url; // Need macros from serde_json for unit tests. #[cfg(test)] #[macro_use] extern crate serde_json; +#[cfg(unix)] #[cfg(test)] extern crate tempfile; #[cfg(test)] diff --git a/edgelet/edgelet-docker/src/module.rs b/edgelet/edgelet-docker/src/module.rs index fb581348ea7..de259ca1cce 100644 --- a/edgelet/edgelet-docker/src/module.rs +++ b/edgelet/edgelet-docker/src/module.rs @@ -4,11 +4,12 @@ use std::str::FromStr; use chrono::prelude::*; use futures::Future; -use hyper::client::Connect; +use hyper::client::connect::Connect; use client::DockerClient; use config::DockerConfig; -use edgelet_core::{pid::Pid, Module, ModuleRuntimeState, ModuleStatus}; +use edgelet_core::pid::Pid; +use edgelet_core::{Module, ModuleRuntimeState, ModuleStatus}; use error::{Error, Result}; pub const MODULE_TYPE: &str = "docker"; @@ -44,10 +45,10 @@ fn status_from_exit_code(exit_code: Option) -> Option { }) } -impl Module for DockerModule { +impl Module for DockerModule { type Config = DockerConfig; type Error = Error; - type RuntimeStateFuture = Box>; + type RuntimeStateFuture = Box + Send>; fn name(&self) -> &str { &self.name @@ -116,25 +117,21 @@ mod tests { use hyper::Client; use serde::Serialize; use time::Duration; - use tokio_core::reactor::Core; + use tokio; use docker::apis::client::APIClient; use docker::apis::configuration::Configuration; use docker::models::{ContainerCreateBody, InlineResponse200, InlineResponse200State}; - use edgelet_core::{pid::Pid, Module, ModuleStatus}; + use edgelet_core::pid::Pid; + use edgelet_core::{Module, ModuleStatus}; use edgelet_test_utils::JsonConnector; use client::DockerClient; use config::DockerConfig; use module::DockerModule; - fn create_api_client( - core: &Core, - body: T, - ) -> DockerClient> { - let client = Client::configure() - .connector(JsonConnector::new(body)) - .build(&core.handle()); + fn create_api_client(body: T) -> DockerClient { + let client = Client::builder().build(JsonConnector::new(&body)); let mut config = Configuration::new(client); config.base_path = "http://localhost/".to_string(); @@ -146,9 +143,8 @@ mod tests { #[test] fn new_instance() { - let core = Core::new().unwrap(); let docker_module = DockerModule::new( - create_api_client(&core, "boo"), + create_api_client("boo"), "mod1", DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); @@ -160,9 +156,8 @@ mod tests { #[test] #[should_panic] fn empty_name_fails() { - let core = Core::new().unwrap(); let _docker_module = DockerModule::new( - create_api_client(&core, "boo"), + create_api_client("boo"), "", DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); @@ -171,9 +166,8 @@ mod tests { #[test] #[should_panic] fn white_space_name_fails() { - let core = Core::new().unwrap(); let _docker_module = DockerModule::new( - create_api_client(&core, "boo"), + create_api_client("boo"), " ", DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); @@ -197,12 +191,10 @@ mod tests { #[test] fn module_status() { let inputs = get_inputs(); - let mut core = Core::new().unwrap(); for &(docker_status, exit_code, ref module_status) in inputs.iter() { let docker_module = DockerModule::new( create_api_client( - &core, InlineResponse200::new().with_state( InlineResponse200State::new() .with_status(docker_status.to_string()) @@ -213,7 +205,10 @@ mod tests { DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); - let state = core.run(docker_module.runtime_state()).unwrap(); + let state = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(docker_module.runtime_state()) + .unwrap(); assert_eq!(module_status, state.status()); } } @@ -222,10 +217,8 @@ mod tests { fn module_runtime_state() { let started_at = Utc::now().to_rfc3339(); let finished_at = (Utc::now() + Duration::hours(1)).to_rfc3339(); - let mut core = Core::new().unwrap(); let docker_module = DockerModule::new( create_api_client( - &core, InlineResponse200::new() .with_state( InlineResponse200State::new() @@ -241,7 +234,10 @@ mod tests { DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); - let runtime_state = core.run(docker_module.runtime_state()).unwrap(); + let runtime_state = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(docker_module.runtime_state()) + .unwrap(); assert_eq!(ModuleStatus::Running, *runtime_state.status()); assert_eq!(10, *runtime_state.exit_code().unwrap()); assert_eq!(&"running", &runtime_state.status_description().unwrap()); @@ -257,10 +253,8 @@ mod tests { fn module_runtime_state_failed_from_dead() { let started_at = Utc::now().to_rfc3339(); let finished_at = (Utc::now() + Duration::hours(1)).to_rfc3339(); - let mut core = Core::new().unwrap(); let docker_module = DockerModule::new( create_api_client( - &core, InlineResponse200::new() .with_state( InlineResponse200State::new() @@ -274,7 +268,10 @@ mod tests { DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); - let runtime_state = core.run(docker_module.runtime_state()).unwrap(); + let runtime_state = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(docker_module.runtime_state()) + .unwrap(); assert_eq!(ModuleStatus::Failed, *runtime_state.status()); assert_eq!(10, *runtime_state.exit_code().unwrap()); assert_eq!(&"dead", &runtime_state.status_description().unwrap()); @@ -289,10 +286,8 @@ mod tests { fn module_runtime_state_with_bad_started_at() { let started_at = "not really a date".to_string(); let finished_at = (Utc::now() + Duration::hours(1)).to_rfc3339(); - let mut core = Core::new().unwrap(); let docker_module = DockerModule::new( create_api_client( - &core, InlineResponse200::new() .with_state( InlineResponse200State::new() @@ -306,7 +301,10 @@ mod tests { DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); - let runtime_state = core.run(docker_module.runtime_state()).unwrap(); + let runtime_state = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(docker_module.runtime_state()) + .unwrap(); assert_eq!(None, runtime_state.started_at()); } @@ -314,10 +312,8 @@ mod tests { fn module_runtime_state_with_bad_finished_at() { let started_at = Utc::now().to_rfc3339(); let finished_at = "nope, not a date".to_string(); - let mut core = Core::new().unwrap(); let docker_module = DockerModule::new( create_api_client( - &core, InlineResponse200::new() .with_state( InlineResponse200State::new() @@ -331,7 +327,10 @@ mod tests { DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); - let runtime_state = core.run(docker_module.runtime_state()).unwrap(); + let runtime_state = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(docker_module.runtime_state()) + .unwrap(); assert_eq!(None, runtime_state.finished_at()); } @@ -339,10 +338,8 @@ mod tests { fn module_runtime_state_with_min_dates() { let started_at = MIN_DATE.to_string(); let finished_at = MIN_DATE.to_string(); - let mut core = Core::new().unwrap(); let docker_module = DockerModule::new( create_api_client( - &core, InlineResponse200::new() .with_state( InlineResponse200State::new() @@ -356,7 +353,10 @@ mod tests { DockerConfig::new("ubuntu", ContainerCreateBody::new(), None).unwrap(), ).unwrap(); - let runtime_state = core.run(docker_module.runtime_state()).unwrap(); + let runtime_state = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(docker_module.runtime_state()) + .unwrap(); assert_eq!(None, runtime_state.started_at()); assert_eq!(None, runtime_state.finished_at()); } diff --git a/edgelet/edgelet-docker/src/runtime.rs b/edgelet/edgelet-docker/src/runtime.rs index 1cfd4a099e8..216d4505f04 100644 --- a/edgelet/edgelet-docker/src/runtime.rs +++ b/edgelet/edgelet-docker/src/runtime.rs @@ -11,7 +11,6 @@ use futures::prelude::*; use hyper::{Body, Chunk as HyperChunk, Client}; use log::Level; use serde_json; -use tokio_core::reactor::Handle; use url::Url; use client::DockerClient; @@ -48,11 +47,9 @@ pub struct DockerModuleRuntime { } impl DockerModuleRuntime { - pub fn new(docker_url: &Url, handle: &Handle) -> Result { + pub fn new(docker_url: &Url) -> Result { // build the hyper client - let client = Client::configure() - .connector(UrlConnector::new(docker_url, handle)?) - .build(handle); + let client = Client::builder().build(UrlConnector::new(docker_url)?); // extract base path - the bit that comes after the scheme let base_path = get_base_path(docker_url); @@ -107,7 +104,7 @@ fn get_base_path(url: &Url) -> &str { impl ModuleRegistry for DockerModuleRuntime { type Error = Error; - type PullFuture = Box>; + type PullFuture = Box + Send>; type RemoveFuture = Box>; type Config = DockerConfig; @@ -158,16 +155,16 @@ impl ModuleRuntime for DockerModuleRuntime { type Chunk = Chunk; type Logs = Logs; - type CreateFuture = Box>; - type InitFuture = Box>; - type ListFuture = Box, Error = Self::Error>>; - type LogsFuture = Box>; - type RemoveFuture = Box>; - type RestartFuture = Box>; - type StartFuture = Box>; - type StopFuture = Box>; - type SystemInfoFuture = Box>; - type RemoveAllFuture = Box>; + type CreateFuture = Box + Send>; + type InitFuture = Box + Send>; + type ListFuture = Box, Error = Self::Error> + Send>; + type LogsFuture = Box + Send>; + type RemoveFuture = Box + Send>; + type RestartFuture = Box + Send>; + type StartFuture = Box + Send>; + type StopFuture = Box + Send>; + type SystemInfoFuture = Box + Send>; + type RemoveAllFuture = Box + Send>; fn init(&self) -> Self::InitFuture { let created = self @@ -352,9 +349,8 @@ impl ModuleRuntime for DockerModuleRuntime { let client_copy = self.client.clone(); let result = serde_json::to_string(&filters) - .and_then(|filters| { - Ok(self - .client + .map(|filters| { + self.client .container_api() .container_list(true, 0, false, &filters) .map(move |containers| { @@ -384,17 +380,15 @@ impl ModuleRuntime for DockerModuleRuntime { config, ) }).collect() - }).map_err(Error::from)) - }).map_err(Error::from); - - match result { - Ok(f) => Box::new(f), - Err(err) => { + }).map_err(Error::from) + }).into_future() + .flatten() + .map_err(|err| { warn!("Attempt to list containers failed."); log_failure(Level::Warn, &err); - Box::new(future::err(err)) - } - } + err + }); + Box::new(result) } fn logs(&self, id: &str, options: &LogOptions) -> Self::LogsFuture { @@ -484,7 +478,7 @@ mod tests { #[cfg(unix)] use tempfile::NamedTempFile; - use tokio_core::reactor::Core; + use tokio; use url::Url; use docker::models::ContainerCreateBody; @@ -495,34 +489,26 @@ mod tests { #[test] #[should_panic(expected = "Invalid uri")] fn invalid_uri_prefix_fails() { - let core = Core::new().unwrap(); - let _mri = DockerModuleRuntime::new( - &Url::parse("foo:///this/is/not/valid").unwrap(), - &core.handle(), - ).unwrap(); + let _mri = + DockerModuleRuntime::new(&Url::parse("foo:///this/is/not/valid").unwrap()).unwrap(); } #[cfg(unix)] #[test] #[should_panic(expected = "Invalid uri")] fn invalid_uds_path_fails() { - let core = Core::new().unwrap(); - let _mri = DockerModuleRuntime::new( - &Url::parse("unix:///this/file/does/not/exist").unwrap(), - &core.handle(), - ).unwrap(); + let _mri = + DockerModuleRuntime::new(&Url::parse("unix:///this/file/does/not/exist").unwrap()) + .unwrap(); } #[cfg(unix)] #[test] fn create_with_uds_succeeds() { - let core = Core::new().unwrap(); let file = NamedTempFile::new().unwrap(); let file_path = file.path().to_str().unwrap(); - let _mri = DockerModuleRuntime::new( - &Url::parse(&format!("unix://{}", file_path)).unwrap(), - &core.handle(), - ).unwrap(); + let _mri = DockerModuleRuntime::new(&Url::parse(&format!("unix://{}", file_path)).unwrap()) + .unwrap(); } fn empty_test(tester: F) @@ -530,10 +516,7 @@ mod tests { F: Fn(&mut DockerModuleRuntime) -> R, R: Future, { - let mut core = Core::new().unwrap(); - let mut mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mut mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = tester(&mut mri).then(|res| match res { Ok(_) => Err("Expected error but got a result.".to_string()), @@ -549,7 +532,10 @@ mod tests { } }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] @@ -604,10 +590,7 @@ mod tests { #[test] fn create_fails_for_non_docker_type() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let module_config = ModuleSpec::new( "m1", @@ -624,15 +607,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn start_fails_for_empty_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = mri.start("").then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -642,15 +625,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn start_fails_for_white_space_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = mri.start(" ").then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -660,15 +643,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn stop_fails_for_empty_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = mri.stop("", None).then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -678,15 +661,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn stop_fails_for_white_space_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = mri.stop(" ", None).then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -696,15 +679,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn restart_fails_for_empty_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = mri.restart("").then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -714,15 +697,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn restart_fails_for_white_space_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = mri.restart(" ").then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -732,15 +715,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn remove_fails_for_empty_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = ModuleRuntime::remove(&mri, "").then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -750,15 +733,15 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn remove_fails_for_white_space_id() { - let mut core = Core::new().unwrap(); - let mri = - DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap(), &core.handle()) - .unwrap(); + let mri = DockerModuleRuntime::new(&Url::parse("http://localhost/").unwrap()).unwrap(); let task = ModuleRuntime::remove(&mri, " ").then(|result| match result { Ok(_) => panic!("Expected test to fail but it didn't!"), @@ -768,6 +751,9 @@ mod tests { }, }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } } diff --git a/edgelet/edgelet-docker/tests/runtime.rs b/edgelet/edgelet-docker/tests/runtime.rs index 7b5a2577f51..0a4aef6b16a 100644 --- a/edgelet/edgelet-docker/tests/runtime.rs +++ b/edgelet/edgelet-docker/tests/runtime.rs @@ -7,7 +7,8 @@ extern crate futures; extern crate hyper; #[macro_use] extern crate serde_json; -extern crate tokio_core; +extern crate tokio; +extern crate typed_headers; extern crate url; extern crate docker; @@ -17,17 +18,13 @@ extern crate edgelet_test_utils; use std::collections::HashMap; use std::str; -use std::sync::mpsc::channel; use std::sync::{Arc, RwLock}; -use std::thread; use std::time::Duration; use futures::prelude::*; use futures::{future, Stream}; -use hyper::header::{ContentLength, ContentType}; -use hyper::server::{Request, Response}; -use hyper::{Error as HyperError, Method, StatusCode}; -use tokio_core::reactor::Core; +use hyper::{Body, Error as HyperError, Method, Request, Response}; +use typed_headers::{mime, ContentLength, ContentType, HeaderMapExt}; use url::form_urlencoded::parse as parse_query; use url::Url; @@ -45,12 +42,14 @@ const IMAGE_NAME: &str = "nginx:latest"; #[cfg(unix)] #[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))] -fn image_pull_handler(req: Request) -> Box> { +fn image_pull_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { // verify that path is /images/create and that the "fromImage" query // parameter has the image name we expect - assert_eq!(req.path(), "/images/create"); + assert_eq!(req.uri().path(), "/images/create"); - let query_map: HashMap = parse_query(req.query().unwrap().as_bytes()) + let query_map: HashMap = parse_query(req.uri().query().unwrap().as_bytes()) .into_owned() .collect(); assert!(query_map.contains_key("fromImage")); @@ -62,13 +61,16 @@ fn image_pull_handler(req: Request) -> Box Box Box> { +fn image_pull_with_creds_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { // verify that path is /images/create and that the "fromImage" query // parameter has the image name we expect - assert_eq!(req.path(), "/images/create"); + assert_eq!(req.uri().path(), "/images/create"); - let query_map: HashMap = parse_query(req.query().unwrap().as_bytes()) + let query_map: HashMap = parse_query(req.uri().query().unwrap().as_bytes()) .into_owned() .collect(); assert!(query_map.contains_key("fromImage")); @@ -120,9 +119,8 @@ fn image_pull_with_creds_handler(req: Request) -> Box>() @@ -139,13 +137,16 @@ fn image_pull_with_creds_handler(req: Request) -> Box Box Box> { - assert_eq!(req.method(), &Method::Delete); - assert_eq!(req.path(), &format!("/images/{}", IMAGE_NAME)); +fn image_remove_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::DELETE); + assert_eq!(req.uri().path(), &format!("/images/{}", IMAGE_NAME)); let response = serde_json::to_string(&vec![ ImageDeleteResponseItem::new().with_deleted(IMAGE_NAME.to_string()), ]).unwrap(); - - Box::new(future::ok( - Response::new() - .with_header(ContentLength(response.len() as u64)) - .with_header(ContentType::json()) - .with_body(response) - .with_status(StatusCode::Ok), - )) + let response_len = response.len(); + + let mut response = Response::new(response.into()); + response + .headers_mut() + .typed_insert(&ContentLength(response_len as u64)); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Box::new(future::ok(response)) } #[test] fn image_remove_succeeds() { - let (sender, receiver) = channel(); - let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server("127.0.0.1", port, image_remove_handler, &sender); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + let server = + run_tcp_server("127.0.0.1", port, image_remove_handler).map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); - let mut mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap(); + let mut mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap(); let task = ModuleRegistry::remove(&mut mri, IMAGE_NAME); - core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } -fn container_create_handler(req: Request) -> Box> { - assert_eq!(req.method(), &Method::Post); - assert_eq!(req.path(), "/containers/create"); +fn container_create_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::POST); + assert_eq!(req.uri().path(), "/containers/create"); let response = json!({ "Id": "12345", "Warnings": [] }).to_string(); + let response_len = response.len(); Box::new( - req.body() + req.into_body() .concat2() .and_then(|body| { let create_options: ContainerCreateBody = @@ -294,27 +292,24 @@ fn container_create_handler(req: Request) -> Box Box> { - assert_eq!(req.method(), &Method::Post); - assert_eq!(req.path(), "/containers/m1/start"); +fn container_start_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::POST); + assert_eq!(req.uri().path(), "/containers/m1/start"); - Box::new(future::ok(Response::new().with_status(StatusCode::Ok))) + Box::new(future::ok(Response::new(Body::empty()))) } #[test] fn container_start_succeeds() { - let (sender, receiver) = channel(); - let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server("127.0.0.1", port, container_start_handler, &sender); - }); + let server = run_tcp_server("127.0.0.1", port, container_start_handler) + .map_err(|err| eprintln!("{}", err)); - // wait for server to get ready - receiver.recv().unwrap(); - - let mut core = Core::new().unwrap(); - let mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap(); + let mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap(); let task = mri.start("m1"); - core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } -fn container_stop_handler(req: Request) -> Box> { - assert_eq!(req.method(), &Method::Post); - assert_eq!(req.path(), "/containers/m1/stop"); +fn container_stop_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::POST); + assert_eq!(req.uri().path(), "/containers/m1/stop"); - Box::new(future::ok(Response::new().with_status(StatusCode::Ok))) + Box::new(future::ok(Response::new(Body::empty()))) } #[test] fn container_stop_succeeds() { - let (sender, receiver) = channel(); - let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server("127.0.0.1", port, container_stop_handler, &sender); - }); + let server = run_tcp_server("127.0.0.1", port, container_stop_handler) + .map_err(|err| eprintln!("{}", err)); - // wait for server to get ready - receiver.recv().unwrap(); - - let mut core = Core::new().unwrap(); - let mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap(); + let mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap(); let task = mri.stop("m1", None); - core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } fn container_stop_with_timeout_handler( - req: Request, -) -> Box> { - assert_eq!(req.method(), &Method::Post); - assert_eq!(req.path(), "/containers/m1/stop"); - assert_eq!(req.query().unwrap(), "t=600"); + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::POST); + assert_eq!(req.uri().path(), "/containers/m1/stop"); + assert_eq!(req.uri().query().unwrap(), "t=600"); - Box::new(future::ok(Response::new().with_status(StatusCode::Ok))) + Box::new(future::ok(Response::new(Body::empty()))) } #[test] fn container_stop_with_timeout_succeeds() { - let (sender, receiver) = channel(); - let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server( - "127.0.0.1", - port, - container_stop_with_timeout_handler, - &sender, - ); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + let server = run_tcp_server("127.0.0.1", port, container_stop_with_timeout_handler) + .map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); - let mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap(); + let mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap(); let task = mri.stop("m1", Some(Duration::from_secs(600))); - core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } -fn container_remove_handler(req: Request) -> Box> { - assert_eq!(req.method(), &Method::Delete); - assert_eq!(req.path(), "/containers/m1"); +fn container_remove_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::DELETE); + assert_eq!(req.uri().path(), "/containers/m1"); - Box::new(future::ok(Response::new().with_status(StatusCode::Ok))) + Box::new(future::ok(Response::new(Body::empty()))) } #[test] fn container_remove_succeeds() { - let (sender, receiver) = channel(); - let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server("127.0.0.1", port, container_remove_handler, &sender); - }); + let server = run_tcp_server("127.0.0.1", port, container_remove_handler) + .map_err(|err| eprintln!("{}", err)); - // wait for server to get ready - receiver.recv().unwrap(); - - let mut core = Core::new().unwrap(); - let mut mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap(); + let mut mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap(); let task = ModuleRuntime::remove(&mut mri, "m1"); - core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } -fn container_list_handler(req: Request) -> Box> { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/containers/json"); +fn container_list_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/containers/json"); - let query_map: HashMap = parse_query(req.query().unwrap().as_bytes()) + let query_map: HashMap = parse_query(req.uri().query().unwrap().as_bytes()) .into_owned() .collect(); assert!(query_map.contains_key("filters")); @@ -567,35 +546,33 @@ fn container_list_handler(req: Request) -> Box Box> { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/containers/mod1/logs"); +fn container_logs_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/containers/mod1/logs"); - let query_map: HashMap = parse_query(req.query().unwrap().as_bytes()) + let query_map: HashMap = parse_query(req.uri().query().unwrap().as_bytes()) .into_owned() .collect(); assert!(query_map.contains_key("stdout")); @@ -646,32 +625,21 @@ fn container_logs_handler(req: Request) -> Box { - let mut list_got_called_w = list_got_called_lock.write().unwrap(); - *list_got_called_w = true; - - assert_eq!(req.path(), "/networks"); - - let response = json!([]).to_string(); - - return Box::new(future::ok( - Response::new() - .with_header(ContentLength(response.len() as u64)) - .with_header(ContentType::json()) - .with_body(response) - .with_status(StatusCode::Ok), - )); - } - &Method::Post => { - //Netowk create. - let mut create_got_called_w = create_got_called_lock.write().unwrap(); - *create_got_called_w = true; - - assert_eq!(req.path(), "/networks/create"); - - let response = json!({ - "Id": "12345", - "Warnings": "" - }).to_string(); - - return Box::new(future::ok( - Response::new() - .with_header(ContentLength(response.len() as u64)) - .with_header(ContentType::json()) - .with_body(response) - .with_status(StatusCode::Ok), - )); - } - _ => panic!("Method is not a get neither a post."), - } - }, - &sender, - ); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + let server = run_tcp_server("127.0.0.1", port, move |req: Request| { + let method = req.method(); + match method { + &Method::GET => { + let mut list_got_called_w = list_got_called_lock.write().unwrap(); + *list_got_called_w = true; + + assert_eq!(req.uri().path(), "/networks"); + + let response = json!([]).to_string(); + let response_len = response.len(); + + let mut response = Response::new(response.into()); + response + .headers_mut() + .typed_insert(&ContentLength(response_len as u64)); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + return Box::new(future::ok(response)); + } + &Method::POST => { + //Netowk create. + let mut create_got_called_w = create_got_called_lock.write().unwrap(); + *create_got_called_w = true; + + assert_eq!(req.uri().path(), "/networks/create"); + + let response = json!({ + "Id": "12345", + "Warnings": "" + }).to_string(); + let response_len = response.len(); + + let mut response = Response::new(response.into()); + response + .headers_mut() + .typed_insert(&ContentLength(response_len as u64)); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + return Box::new(future::ok(response)); + } + _ => panic!("Method is not a get neither a post."), + } + }).map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); - let mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap() - .with_network_id("azure-iot-edge".to_string()); + let mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap() + .with_network_id("azure-iot-edge".to_string()); //act let task = mri.init(); - core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); //assert assert_eq!(true, *list_got_called_lock_cloned.read().unwrap()); @@ -772,9 +735,6 @@ fn runtime_init_network_does_not_exist_create() { #[test] fn runtime_init_network_exist_do_not_create() { - //arrange - let (sender, receiver) = channel(); - let list_got_called_lock = Arc::new(RwLock::new(false)); let list_got_called_lock_cloned = list_got_called_lock.clone(); @@ -785,21 +745,20 @@ fn runtime_init_network_exist_do_not_create() { //let mut got_called = false; - thread::spawn(move || { + let server = run_tcp_server( "127.0.0.1", port, - move |req: Request| { + move |req: Request| { let method = req.method(); match method { - &Method::Get => { + &Method::GET => { let mut list_got_called_w = list_got_called_lock.write().unwrap(); *list_got_called_w = true; - assert_eq!(req.path(), "/networks"); + assert_eq!(req.uri().path(), "/networks"); - let response = json!( - [ + let response = json!([ { "Name": "azure-iot-edge", "Id": "8e3209d08ed5e73d1c9c8e7580ddad232b6dceb5bf0c6d74cadbed75422eef0e", @@ -817,57 +776,49 @@ fn runtime_init_network_exist_do_not_create() { "Containers": {}, "Options": {} } - ] - ).to_string(); - - return Box::new(future::ok( - Response::new() - .with_header(ContentLength(response.len() as u64)) - .with_header(ContentType::json()) - .with_body(response) - .with_status(StatusCode::Ok), - )); + ]).to_string(); + let response_len = response.len(); + + let mut response = Response::new(response.into()); + response.headers_mut().typed_insert(&ContentLength(response_len as u64)); + response.headers_mut().typed_insert(&ContentType(mime::APPLICATION_JSON)); + return Box::new(future::ok(response)); } - &Method::Post => { + &Method::POST => { //Netowk create. let mut create_got_called_w = create_got_called_lock.write().unwrap(); *create_got_called_w = true; - assert_eq!(req.path(), "/networks/create"); + assert_eq!(req.uri().path(), "/networks/create"); let response = json!({ - "Id": "12345", - "Warnings": "" - }).to_string(); - - return Box::new(future::ok( - Response::new() - .with_header(ContentLength(response.len() as u64)) - .with_header(ContentType::json()) - .with_body(response) - .with_status(StatusCode::Ok), - )); + "Id": "12345", + "Warnings": "" + }).to_string(); + let response_len = response.len(); + + let mut response = Response::new(response.into()); + response.headers_mut().typed_insert(&ContentLength(response_len as u64)); + response.headers_mut().typed_insert(&ContentType(mime::APPLICATION_JSON)); + return Box::new(future::ok(response)); } _ => panic!("Method is not a get neither a post."), } }, - &sender, - ); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + ) + .map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); - let mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap() - .with_network_id("azure-iot-edge".to_string()); + let mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap() + .with_network_id("azure-iot-edge".to_string()); //act let task = mri.init(); - core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); //assert assert_eq!(true, *list_got_called_lock_cloned.read().unwrap()); @@ -876,62 +827,51 @@ fn runtime_init_network_exist_do_not_create() { #[test] fn runtime_system_info_succeed() { - //arrange - let (sender, receiver) = channel(); - let system_info_got_called_lock = Arc::new(RwLock::new(false)); let system_info_got_called_lock_cloned = system_info_got_called_lock.clone(); let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server( - "127.0.0.1", - port, - move |req: Request| { - let method = req.method(); - match method { - &Method::Get => { - let mut system_info_got_called_w = - system_info_got_called_lock.write().unwrap(); - *system_info_got_called_w = true; - - assert_eq!(req.path(), "/info"); - - let response = json!( - { - "OSType": "linux", - "Architecture": "x86_64", - } - ).to_string(); - - return Box::new(future::ok( - Response::new() - .with_header(ContentLength(response.len() as u64)) - .with_header(ContentType::json()) - .with_body(response) - .with_status(StatusCode::Ok), - )); - } - _ => panic!("Method is not a get neither a post."), - } - }, - &sender, - ); - }); + let server = run_tcp_server("127.0.0.1", port, move |req: Request| { + let method = req.method(); + match method { + &Method::GET => { + let mut system_info_got_called_w = system_info_got_called_lock.write().unwrap(); + *system_info_got_called_w = true; + + assert_eq!(req.uri().path(), "/info"); + + let response = json!( + { + "OSType": "linux", + "Architecture": "x86_64", + } + ).to_string(); + let response_len = response.len(); + + let mut response = Response::new(response.into()); + response + .headers_mut() + .typed_insert(&ContentLength(response_len as u64)); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + return Box::new(future::ok(response)); + } + _ => panic!("Method is not a get neither a post."), + } + }).map_err(|err| eprintln!("{}", err)); - // wait for server to get ready - receiver.recv().unwrap(); - - let mut core = Core::new().unwrap(); - let mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap(); + let mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap(); //act let task = mri.system_info(); - let system_info = core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + let system_info = runtime.block_on(task).unwrap(); //assert assert_eq!(true, *system_info_got_called_lock_cloned.read().unwrap()); @@ -941,57 +881,46 @@ fn runtime_system_info_succeed() { #[test] fn runtime_system_info_none_returns_unkown() { - //arrange - let (sender, receiver) = channel(); - let system_info_got_called_lock = Arc::new(RwLock::new(false)); let system_info_got_called_lock_cloned = system_info_got_called_lock.clone(); let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server( - "127.0.0.1", - port, - move |req: Request| { - let method = req.method(); - match method { - &Method::Get => { - let mut system_info_got_called_w = - system_info_got_called_lock.write().unwrap(); - *system_info_got_called_w = true; - - assert_eq!(req.path(), "/info"); - - let response = json!({}).to_string(); - - return Box::new(future::ok( - Response::new() - .with_header(ContentLength(response.len() as u64)) - .with_header(ContentType::json()) - .with_body(response) - .with_status(StatusCode::Ok), - )); - } - _ => panic!("Method is not a get neither a post."), - } - }, - &sender, - ); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + let server = run_tcp_server("127.0.0.1", port, move |req: Request| { + let method = req.method(); + match method { + &Method::GET => { + let mut system_info_got_called_w = system_info_got_called_lock.write().unwrap(); + *system_info_got_called_w = true; + + assert_eq!(req.uri().path(), "/info"); + + let response = json!({}).to_string(); + let response_len = response.len(); + + let mut response = Response::new(response.into()); + response + .headers_mut() + .typed_insert(&ContentLength(response_len as u64)); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + return Box::new(future::ok(response)); + } + _ => panic!("Method is not a get neither a post."), + } + }).map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); - let mri = DockerModuleRuntime::new( - &Url::parse(&format!("http://localhost:{}/", port)).unwrap(), - &core.handle(), - ).unwrap(); + let mri = + DockerModuleRuntime::new(&Url::parse(&format!("http://localhost:{}/", port)).unwrap()) + .unwrap(); //act let task = mri.system_info(); - let system_info = core.run(task).unwrap(); + + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + let system_info = runtime.block_on(task).unwrap(); //assert assert_eq!(true, *system_info_got_called_lock_cloned.read().unwrap()); diff --git a/edgelet/edgelet-hsm/src/crypto.rs b/edgelet/edgelet-hsm/src/crypto.rs index dc6cf155885..7af5a5b243b 100644 --- a/edgelet/edgelet-hsm/src/crypto.rs +++ b/edgelet/edgelet-hsm/src/crypto.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, Mutex}; use certificate_properties::convert_properties; use edgelet_core::{ @@ -25,7 +25,7 @@ use hsm::{ /// Activate a private key, and then you can use that key to sign data. #[derive(Clone)] pub struct Crypto { - crypto: Arc>, + crypto: Arc>, } impl Crypto { @@ -36,7 +36,7 @@ impl Crypto { pub fn from_hsm(crypto: HsmCrypto) -> Result { Ok(Crypto { - crypto: Arc::new(RwLock::new(crypto)), + crypto: Arc::new(Mutex::new(crypto)), }) } } @@ -44,8 +44,8 @@ impl Crypto { impl CoreMasterEncryptionKey for Crypto { fn create_key(&self) -> Result<(), CoreError> { self.crypto - .read() - .expect("Shared read lock on crypto structure failed") + .lock() + .expect("Lock on crypto structure failed") .create_master_encryption_key() .map_err(Error::from) .map_err(CoreError::from) @@ -53,8 +53,8 @@ impl CoreMasterEncryptionKey for Crypto { fn destroy_key(&self) -> Result<(), CoreError> { self.crypto - .read() - .expect("Shared read lock on crypto structure failed") + .lock() + .expect("Lock on crypto structure failed") .destroy_master_encryption_key() .map_err(Error::from) .map_err(CoreError::from) @@ -68,10 +68,7 @@ impl CoreCreateCertificate for Crypto { &self, properties: &CoreCertificateProperties, ) -> Result { - let crypto = self - .crypto - .read() - .expect("Shared read lock on crypto structure failed"); + let crypto = self.crypto.lock().expect("Lock on crypto structure failed"); let device_ca_alias = crypto.get_device_ca_alias(); let cert = crypto .create_certificate(&convert_properties(properties, &device_ca_alias)) @@ -82,8 +79,8 @@ impl CoreCreateCertificate for Crypto { fn destroy_certificate(&self, alias: String) -> Result<(), CoreError> { self.crypto - .read() - .expect("Shared read lock on crypto structure failed") + .lock() + .expect("Lock on crypto structure failed") .destroy_certificate(alias) .map_err(Error::from) .map_err(CoreError::from)?; @@ -101,8 +98,8 @@ impl CoreEncrypt for Crypto { initialization_vector: &[u8], ) -> Result { self.crypto - .read() - .expect("Shared read lock on crypto structure failed") + .lock() + .expect("Lock on crypto structure failed") .encrypt(client_id, plaintext, initialization_vector) .map_err(Error::from) .map_err(CoreError::from) @@ -119,8 +116,8 @@ impl CoreDecrypt for Crypto { initialization_vector: &[u8], ) -> Result { self.crypto - .read() - .expect("Shared read lock on crypto structure failed") + .lock() + .expect("Lock on crypto structure failed") .decrypt(client_id, ciphertext, initialization_vector) .map_err(Error::from) .map_err(CoreError::from) @@ -133,8 +130,8 @@ impl CoreGetTrustBundle for Crypto { fn get_trust_bundle(&self) -> Result { let cert = self .crypto - .read() - .expect("Shared lock on crypto structure failed") + .lock() + .expect("Lock on crypto structure failed") .get_trust_bundle() .map_err(Error::from) .map_err(CoreError::from)?; diff --git a/edgelet/edgelet-hsm/src/lib.rs b/edgelet/edgelet-hsm/src/lib.rs index b9756d3d705..4eddc04654a 100644 --- a/edgelet/edgelet-hsm/src/lib.rs +++ b/edgelet/edgelet-hsm/src/lib.rs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#![deny(unused_extern_crates, warnings)] + extern crate bytes; extern crate edgelet_core; #[macro_use] diff --git a/edgelet/edgelet-hsm/src/tpm.rs b/edgelet/edgelet-hsm/src/tpm.rs index 4d2a5829b01..2afdfb25b1a 100644 --- a/edgelet/edgelet-hsm/src/tpm.rs +++ b/edgelet/edgelet-hsm/src/tpm.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -use std::sync::{Arc, RwLock}; +use std::sync::{Arc, Mutex}; use bytes::Bytes; @@ -17,7 +17,7 @@ const ROOT_KEY_NAME: &str = "primary"; /// Represents a key which can sign data. #[derive(Clone)] pub struct TpmKey { - tpm: Arc>, + tpm: Arc>, identity: KeyIdentity, key_name: String, } @@ -26,7 +26,7 @@ pub struct TpmKey { /// Activate a private key, and then you can use that key to sign data. #[derive(Clone)] pub struct TpmKeyStore { - tpm: Arc>, + tpm: Arc>, } impl TpmKeyStore { @@ -37,15 +37,15 @@ impl TpmKeyStore { pub fn from_hsm(tpm: Tpm) -> Result { Ok(TpmKeyStore { - tpm: Arc::new(RwLock::new(tpm)), + tpm: Arc::new(Mutex::new(tpm)), }) } /// Activate and store a private key in the TPM. pub fn activate_key(&self, key_value: &Bytes) -> Result<(), Error> { self.tpm - .read() - .expect("Read lock on KeyStore TPM failed") + .lock() + .expect("Lock on KeyStore TPM failed") .activate_identity_key(key_value) .map_err(Error::from)?; Ok(()) @@ -117,15 +117,15 @@ impl Sign for TpmKey { match self.identity { KeyIdentity::Device => self .tpm - .read() - .expect("Read lock failed") + .lock() + .expect("Lock failed") .sign_with_identity(data) .map_err(Error::from) .map_err(CoreError::from), KeyIdentity::Module(ref _m) => self .tpm - .read() - .expect("Read lock failed") + .lock() + .expect("Lock failed") .derive_and_sign_with_identity( data, format!( diff --git a/edgelet/edgelet-http-mgmt/Cargo.toml b/edgelet/edgelet-http-mgmt/Cargo.toml index ffac6181c3d..7af40c51a57 100644 --- a/edgelet/edgelet-http-mgmt/Cargo.toml +++ b/edgelet/edgelet-http-mgmt/Cargo.toml @@ -9,13 +9,12 @@ failure = "0.1" failure_derive = "0.1" futures = "0.1" http = "0.1" -hyper = { version = "0.11", features = ["compat"] } +hyper = "0.12" lazy_static = "1.0" log = "0.4" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -tokio-core = "0.1" url = "1.7" edgelet-core = { path = "../edgelet-core" } diff --git a/edgelet/edgelet-http-mgmt/src/client/module.rs b/edgelet/edgelet-http-mgmt/src/client/module.rs index 0f270cfe881..bdb263bb095 100644 --- a/edgelet/edgelet-http-mgmt/src/client/module.rs +++ b/edgelet/edgelet-http-mgmt/src/client/module.rs @@ -1,8 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. use std::fmt; -use std::rc::Rc; use std::str::FromStr; +use std::sync::Arc; use std::time::Duration; use edgelet_core::SystemInfo as CoreSystemInfo; @@ -11,26 +11,22 @@ use edgelet_docker::{self, DockerConfig}; use edgelet_http::{UrlConnector, API_VERSION}; use futures::future::{self, FutureResult}; use futures::prelude::*; -use hyper::client::Client; -use hyper::{Body, Chunk as HyperChunk}; +use hyper::{Body, Chunk as HyperChunk, Client}; use management::apis::client::APIClient; use management::apis::configuration::Configuration; use management::models::{Config, ModuleDetails as HttpModuleDetails}; use serde_json; -use tokio_core::reactor::Handle; use url::Url; use error::{Error, ErrorKind}; pub struct ModuleClient { - client: Rc>, + client: Arc>, } impl ModuleClient { - pub fn new(url: &Url, handle: &Handle) -> Result { - let client = Client::configure() - .connector(UrlConnector::new(url, handle)?) - .build(handle); + pub fn new(url: &Url) -> Result { + let client = Client::builder().build(UrlConnector::new(url)?); let base_path = get_base_path(url); let mut configuration = Configuration::new(client); @@ -42,7 +38,7 @@ impl ModuleClient { }); let module_client = ModuleClient { - client: Rc::new(APIClient::new(configuration)), + client: Arc::new(APIClient::new(configuration)), }; Ok(module_client) } @@ -147,16 +143,16 @@ impl ModuleRuntime for ModuleClient { type Chunk = Chunk; type Logs = Logs; - type CreateFuture = Box>; + type CreateFuture = Box + Send>; type InitFuture = FutureResult<(), Self::Error>; - type ListFuture = Box, Error = Self::Error>>; - type LogsFuture = Box>; - type RemoveFuture = Box>; - type RestartFuture = Box>; - type StartFuture = Box>; - type StopFuture = Box>; - type SystemInfoFuture = Box>; - type RemoveAllFuture = Box>; + type ListFuture = Box, Error = Self::Error> + Send>; + type LogsFuture = Box + Send>; + type RemoveFuture = Box + Send>; + type RestartFuture = Box + Send>; + type StartFuture = Box + Send>; + type StopFuture = Box + Send>; + type SystemInfoFuture = Box + Send>; + type RemoveAllFuture = Box + Send>; fn system_info(&self) -> Self::SystemInfoFuture { unimplemented!() diff --git a/edgelet/edgelet-http-mgmt/src/error.rs b/edgelet/edgelet-http-mgmt/src/error.rs index b8d13f232d1..d64d5693c8f 100644 --- a/edgelet/edgelet-http-mgmt/src/error.rs +++ b/edgelet/edgelet-http-mgmt/src/error.rs @@ -112,12 +112,6 @@ impl From for Error { } } -impl From for HyperError { - fn from(_error: Error) -> HyperError { - HyperError::Method - } -} - impl From for Error { fn from(error: HttpError) -> Error { Error { @@ -139,7 +133,7 @@ impl From> for Error { match error { MgmtError::Hyper(h) => From::from(h), MgmtError::Serde(s) => From::from(s), - MgmtError::ApiError(ref e) if e.code == HyperStatusCode::NotModified => { + MgmtError::ApiError(ref e) if e.code == HyperStatusCode::NOT_MODIFIED => { From::from(ErrorKind::NotModified) } MgmtError::ApiError(_) => From::from(ErrorKind::Client(error)), diff --git a/edgelet/edgelet-http-mgmt/src/lib.rs b/edgelet/edgelet-http-mgmt/src/lib.rs index ca880ea3cc5..2ec25cb4617 100644 --- a/edgelet/edgelet-http-mgmt/src/lib.rs +++ b/edgelet/edgelet-http-mgmt/src/lib.rs @@ -1,6 +1,11 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] +// Remove this when clippy stops warning about old-style `allow()`, +// which can only be silenced by enabling a feature and thus requires nightly +// +// Ref: https://github.com/rust-lang-nursery/rust-clippy/issues/3159#issuecomment-420530386 +#![allow(renamed_and_removed_lints)] #[cfg(test)] extern crate chrono; @@ -29,7 +34,6 @@ extern crate serde; extern crate serde_json; #[cfg(not(test))] extern crate serde_json; -extern crate tokio_core; extern crate url; use http::Response; diff --git a/edgelet/edgelet-http-mgmt/src/server/identity/create.rs b/edgelet/edgelet-http-mgmt/src/server/identity/create.rs index f7b29f438b7..d5282f703c2 100644 --- a/edgelet/edgelet-http-mgmt/src/server/identity/create.rs +++ b/edgelet/edgelet-http-mgmt/src/server/identity/create.rs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -use std::cell::RefCell; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use failure::ResultExt; use futures::future::{self, FutureResult}; @@ -13,7 +12,7 @@ use serde::Serialize; use serde_json; use edgelet_core::{Identity as CoreIdentity, IdentityManager, IdentitySpec}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use management::models::{Identity, IdentitySpec as CreateIdentitySpec}; use error::{Error, ErrorKind}; @@ -25,7 +24,7 @@ where I::Identity: Serialize, ::Error: IntoResponse, { - id_manager: Arc>, + id_manager: Arc>, } impl CreateIdentity @@ -36,14 +35,14 @@ where { pub fn new(id_manager: I) -> Self { CreateIdentity { - id_manager: Arc::new(RefCell::new(id_manager)), + id_manager: Arc::new(Mutex::new(id_manager)), } } } impl Handler for CreateIdentity where - I: 'static + IdentityManager, + I: 'static + IdentityManager + Send, I::Identity: CoreIdentity + Serialize, ::Error: IntoResponse, { @@ -51,12 +50,12 @@ where &self, req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let id_mgr = self.id_manager.clone(); let response = read_request(req) .and_then(move |spec| { - let mut rid = id_mgr.borrow_mut(); + let mut rid = id_mgr.lock().unwrap(); rid.create(spec) .map(|identity| { let identity = Identity::new( diff --git a/edgelet/edgelet-http-mgmt/src/server/identity/delete.rs b/edgelet/edgelet-http-mgmt/src/server/identity/delete.rs index ddeb6f12058..29351e4b4ef 100644 --- a/edgelet/edgelet-http-mgmt/src/server/identity/delete.rs +++ b/edgelet/edgelet-http-mgmt/src/server/identity/delete.rs @@ -1,9 +1,9 @@ // Copyright (c) Microsoft. All rights reserved. -use std::cell::RefCell; +use std::sync::Mutex; use edgelet_core::{IdentityManager, IdentitySpec}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use futures::{future, Future}; use http::{Request, Response, StatusCode}; use hyper::{Body, Error as HyperError}; @@ -16,7 +16,7 @@ where I: 'static + IdentityManager, ::Error: IntoResponse, { - id_manager: RefCell, + id_manager: Mutex, } impl DeleteIdentity @@ -26,28 +26,29 @@ where { pub fn new(id_manager: I) -> Self { DeleteIdentity { - id_manager: RefCell::new(id_manager), + id_manager: Mutex::new(id_manager), } } } impl Handler for DeleteIdentity where - I: 'static + IdentityManager, + I: 'static + IdentityManager + Send, ::Error: IntoResponse, { fn handle( &self, _req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = params .name("name") .ok_or_else(|| Error::from(ErrorKind::BadParam)) .map(|name| { let result = self .id_manager - .borrow_mut() + .lock() + .unwrap() .delete(IdentitySpec::new(name)) .map(|_| { Response::builder() @@ -89,7 +90,7 @@ mod tests { let response = handler.handle(request, parameters).wait().unwrap(); assert_eq!(StatusCode::NO_CONTENT, response.status()); - let list = handler.id_manager.borrow().list().wait().unwrap(); + let list = handler.id_manager.lock().unwrap().list().wait().unwrap(); assert_eq!(2, list.len()); assert_eq!( None, diff --git a/edgelet/edgelet-http-mgmt/src/server/identity/list.rs b/edgelet/edgelet-http-mgmt/src/server/identity/list.rs index e59dc51bd89..1acea953e90 100644 --- a/edgelet/edgelet-http-mgmt/src/server/identity/list.rs +++ b/edgelet/edgelet-http-mgmt/src/server/identity/list.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::{Identity as CoreIdentity, IdentityManager}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use failure::ResultExt; use futures::{future, Future}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; @@ -34,14 +34,14 @@ where impl Handler for ListIdentities where - I: 'static + IdentityManager, + I: 'static + IdentityManager + Send, I::Identity: Serialize, { fn handle( &self, _req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = self.id_manager.list().then(|result| { result .context(ErrorKind::IdentityManager) diff --git a/edgelet/edgelet-http-mgmt/src/server/identity/update.rs b/edgelet/edgelet-http-mgmt/src/server/identity/update.rs index 70c450bceff..43ea8362d22 100644 --- a/edgelet/edgelet-http-mgmt/src/server/identity/update.rs +++ b/edgelet/edgelet-http-mgmt/src/server/identity/update.rs @@ -1,7 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -use std::cell::RefCell; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use failure::ResultExt; use futures::future::{self, Either, FutureResult}; @@ -13,7 +12,7 @@ use serde::Serialize; use serde_json; use edgelet_core::{Identity as CoreIdentity, IdentityManager, IdentitySpec}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use management::models::{Identity, UpdateIdentity as UpdateIdentityRequest}; use error::{Error, ErrorKind}; @@ -25,7 +24,7 @@ where I::Identity: Serialize, ::Error: IntoResponse, { - id_manager: Arc>, + id_manager: Arc>, } impl UpdateIdentity @@ -36,14 +35,14 @@ where { pub fn new(id_manager: I) -> Self { UpdateIdentity { - id_manager: Arc::new(RefCell::new(id_manager)), + id_manager: Arc::new(Mutex::new(id_manager)), } } } impl Handler for UpdateIdentity where - I: 'static + IdentityManager, + I: 'static + IdentityManager + Send, I::Identity: CoreIdentity + Serialize, ::Error: IntoResponse, { @@ -51,7 +50,7 @@ where &self, req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let id_manager = self.id_manager.clone(); let response = params .name("name") @@ -59,7 +58,7 @@ where .map(|name| { let result = read_request(name, req) .and_then(move |spec| { - let mut rid = id_manager.borrow_mut(); + let mut rid = id_manager.lock().unwrap(); rid.update(spec) .map(|id| write_response(&id)) .or_else(|e| future::ok(e.into_response())) diff --git a/edgelet/edgelet-http-mgmt/src/server/mod.rs b/edgelet/edgelet-http-mgmt/src/server/mod.rs index 5c43a254691..d4443e631e0 100644 --- a/edgelet/edgelet-http-mgmt/src/server/mod.rs +++ b/edgelet/edgelet-http-mgmt/src/server/mod.rs @@ -4,16 +4,17 @@ mod identity; mod module; mod system_info; -use std::io; +use std::error::Error as StdError; use edgelet_core::{ Error as CoreError, IdentityManager, Module, ModuleRegistry, ModuleRuntime, Policy, }; use edgelet_http::authorization::Authorization; use edgelet_http::route::*; -use http::{Request, Response}; -use hyper::server::{NewService, Service}; -use hyper::{Body, Error as HyperError}; +use failure; +use futures::{future, Future}; +use hyper::service::{NewService, Service}; +use hyper::{Body, Request}; use serde::de::DeserializeOwned; use serde::Serialize; @@ -33,16 +34,18 @@ pub struct ManagementService { } impl ManagementService { - pub fn new(runtime: &M, identity: &I) -> Result + // clippy bug: https://github.com/rust-lang-nursery/rust-clippy/issues/3220 + #[cfg_attr(feature = "cargo-clippy", allow(new_ret_no_self))] + pub fn new(runtime: &M, identity: &I) -> impl Future where - M: 'static + ModuleRuntime + Clone, + M: 'static + ModuleRuntime + Clone + Send + Sync, ::Config: DeserializeOwned + Serialize, M::Error: IntoResponse, M::Error: Into, ::Error: Into, M::Logs: Into, ::Error: IntoResponse, - I: 'static + IdentityManager + Clone, + I: 'static + IdentityManager + Clone + Send + Sync, I::Identity: Serialize, I::Error: IntoResponse, { @@ -64,30 +67,34 @@ impl ManagementService { get "/systeminfo" => Authorization::new(GetSystemInfo::new(runtime.clone()), Policy::Anonymous, runtime.clone()), ); - let inner = router.new_service()?; - let service = ManagementService { inner }; - Ok(service) + + router + .new_service() + .map(|inner| ManagementService { inner }) + .map_err(failure::Error::from_boxed_compat) } } impl Service for ManagementService { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Future = BoxFuture; + type ReqBody = as Service>::ReqBody; + type ResBody = as Service>::ResBody; + type Error = as Service>::Error; + type Future = as Service>::Future; - fn call(&self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { self.inner.call(req) } } impl NewService for ManagementService { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Instance = Self; + type ReqBody = ::ReqBody; + type ResBody = ::ResBody; + type Error = ::Error; + type Service = Self; + type Future = future::FutureResult; + type InitError = Box; - fn new_service(&self) -> io::Result { - Ok(self.clone()) + fn new_service(&self) -> Self::Future { + future::ok(self.clone()) } } diff --git a/edgelet/edgelet-http-mgmt/src/server/module/create.rs b/edgelet/edgelet-http-mgmt/src/server/module/create.rs index 6570f255b00..25f4fc119e7 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/create.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/create.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::{Module, ModuleRegistry, ModuleRuntime, ModuleStatus}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use failure::ResultExt; use futures::{future, Future, Stream}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; @@ -36,7 +36,7 @@ where impl Handler for CreateModule where - M: 'static + ModuleRuntime + Clone, + M: 'static + ModuleRuntime + Clone + Send, ::Config: DeserializeOwned + Serialize, M::Error: IntoResponse, ::Error: IntoResponse, @@ -45,7 +45,7 @@ where &self, req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let runtime = self.runtime.clone(); let response = req .into_body() diff --git a/edgelet/edgelet-http-mgmt/src/server/module/delete.rs b/edgelet/edgelet-http-mgmt/src/server/module/delete.rs index 5e8ad8b3419..dc279772bbe 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/delete.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/delete.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::ModuleRuntime; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use futures::{future, Future}; use http::{Request, Response, StatusCode}; use hyper::{Body, Error as HyperError}; @@ -29,14 +29,14 @@ where impl Handler for DeleteModule where - M: 'static + ModuleRuntime, + M: 'static + ModuleRuntime + Send, ::Error: IntoResponse, { fn handle( &self, _req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = params .name("name") .ok_or_else(|| Error::from(ErrorKind::BadParam)) diff --git a/edgelet/edgelet-http-mgmt/src/server/module/get.rs b/edgelet/edgelet-http-mgmt/src/server/module/get.rs index e50534704da..5272d18ef75 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/get.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/get.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. -use edgelet_http::route::{BoxFuture, Handler, Parameters}; -use futures::future; +use edgelet_http::route::{Handler, Parameters}; +use futures::{future, Future}; use http::{Request, Response}; use hyper::{Body, Error as HyperError}; @@ -12,7 +12,7 @@ impl Handler for GetModule { &self, _req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = Response::new(Body::default()); Box::new(future::ok(response)) } diff --git a/edgelet/edgelet-http-mgmt/src/server/module/list.rs b/edgelet/edgelet-http-mgmt/src/server/module/list.rs index 04ebda2879a..04af2f348cd 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/list.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/list.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::{Module, ModuleRuntime}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use failure::ResultExt; use futures::{future, Future}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; @@ -35,14 +35,14 @@ where impl Handler for ListModules where - M: 'static + ModuleRuntime, + M: 'static + ModuleRuntime + Send, ::Config: Serialize, { fn handle( &self, _req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { debug!("List modules"); let response = self.runtime diff --git a/edgelet/edgelet-http-mgmt/src/server/module/logs.rs b/edgelet/edgelet-http-mgmt/src/server/module/logs.rs index 57562a63162..cc819384764 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/logs.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/logs.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::{LogOptions, LogTail, ModuleRuntime}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use failure::ResultExt; use futures::{future, Future}; use http::{Request, Response, StatusCode}; @@ -29,7 +29,7 @@ where impl Handler for ModuleLogs where - M: 'static + ModuleRuntime + Clone, + M: 'static + ModuleRuntime + Clone + Send, M::Error: IntoResponse, M::Logs: Into, { @@ -37,7 +37,7 @@ where &self, req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let runtime = self.runtime.clone(); let response = params .name("name") diff --git a/edgelet/edgelet-http-mgmt/src/server/module/mod.rs b/edgelet/edgelet-http-mgmt/src/server/module/mod.rs index c1b35e1dc0b..0cd75c87ade 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/mod.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/mod.rs @@ -78,9 +78,9 @@ impl IntoResponse for DockerError { } } -fn core_to_details(module: M) -> Box> +fn core_to_details(module: M) -> Box + Send> where - M: 'static + Module, + M: 'static + Module + Send, M::Config: Serialize, { let details = module diff --git a/edgelet/edgelet-http-mgmt/src/server/module/restart.rs b/edgelet/edgelet-http-mgmt/src/server/module/restart.rs index 68eee515886..91b8e612dbf 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/restart.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/restart.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::ModuleRuntime; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use futures::{future, Future}; use http::{Request, Response, StatusCode}; use hyper::{Body, Error as HyperError}; @@ -29,14 +29,14 @@ where impl Handler for RestartModule where - M: 'static + ModuleRuntime, + M: 'static + ModuleRuntime + Send, ::Error: IntoResponse, { fn handle( &self, _req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = params .name("name") .ok_or_else(|| Error::from(ErrorKind::BadParam)) diff --git a/edgelet/edgelet-http-mgmt/src/server/module/start.rs b/edgelet/edgelet-http-mgmt/src/server/module/start.rs index 32b90f2d4d4..cbfb59260b4 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/start.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/start.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::ModuleRuntime; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use futures::{future, Future}; use http::{Request, Response, StatusCode}; use hyper::{Body, Error as HyperError}; @@ -29,14 +29,14 @@ where impl Handler for StartModule where - M: 'static + ModuleRuntime, + M: 'static + ModuleRuntime + Send, ::Error: IntoResponse, { fn handle( &self, _req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = params .name("name") .ok_or_else(|| Error::from(ErrorKind::BadParam)) diff --git a/edgelet/edgelet-http-mgmt/src/server/module/stop.rs b/edgelet/edgelet-http-mgmt/src/server/module/stop.rs index 839a954dc09..3477fbc30f4 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/stop.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/stop.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::ModuleRuntime; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use futures::{future, Future}; use http::{Request, Response, StatusCode}; use hyper::{Body, Error as HyperError}; @@ -29,14 +29,14 @@ where impl Handler for StopModule where - M: 'static + ModuleRuntime, + M: 'static + ModuleRuntime + Send, ::Error: IntoResponse, { fn handle( &self, _req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = params .name("name") .ok_or_else(|| Error::from(ErrorKind::BadParam)) diff --git a/edgelet/edgelet-http-mgmt/src/server/module/update.rs b/edgelet/edgelet-http-mgmt/src/server/module/update.rs index 542894e43e2..e5e4851ee19 100644 --- a/edgelet/edgelet-http-mgmt/src/server/module/update.rs +++ b/edgelet/edgelet-http-mgmt/src/server/module/update.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::{Module, ModuleRegistry, ModuleRuntime, ModuleStatus}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use failure::ResultExt; use futures::{future, Future, Stream}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; @@ -37,7 +37,7 @@ where impl Handler for UpdateModule where - M: 'static + ModuleRuntime + Clone, + M: 'static + ModuleRuntime + Clone + Send, ::Config: DeserializeOwned + Serialize, M::Error: IntoResponse, ::Error: IntoResponse, @@ -46,7 +46,7 @@ where &self, req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let runtime = self.runtime.clone(); let start: bool = req .uri() diff --git a/edgelet/edgelet-http-mgmt/src/server/system_info/get.rs b/edgelet/edgelet-http-mgmt/src/server/system_info/get.rs index 7146d178aff..aad8f8b6fd9 100644 --- a/edgelet/edgelet-http-mgmt/src/server/system_info/get.rs +++ b/edgelet/edgelet-http-mgmt/src/server/system_info/get.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. use edgelet_core::{Module, ModuleRuntime}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use failure::ResultExt; use futures::{future, Future}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; @@ -36,7 +36,7 @@ where impl Handler for GetSystemInfo where - M: 'static + ModuleRuntime, + M: 'static + ModuleRuntime + Send, M::Error: IntoResponse, ::Config: Serialize, { @@ -44,7 +44,7 @@ where &self, _req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { debug!("Get System Information"); let response = self .runtime diff --git a/edgelet/edgelet-http-workload/Cargo.toml b/edgelet/edgelet-http-workload/Cargo.toml index 32b7dfe85b2..d444f64a004 100644 --- a/edgelet/edgelet-http-workload/Cargo.toml +++ b/edgelet/edgelet-http-workload/Cargo.toml @@ -7,17 +7,15 @@ publish = false [dependencies] base64 = "0.9" chrono = { version = "0.4", features = ["serde"] } -failure = "0.1" +failure = "0.1.2" failure_derive = "0.1" futures = "0.1" http = "0.1" -hyper = { version = "0.11", features = ["compat"] } +hyper = "0.12" log = "0.4" -serde = "1.0" serde_json = "1.0" edgelet-core = { path = "../edgelet-core" } -edgelet-hsm = { path = "../edgelet-hsm" } edgelet-http = { path = "../edgelet-http" } edgelet-utils = { path = "../edgelet-utils" } workload = { path = "../workload" } diff --git a/edgelet/edgelet-http-workload/src/error.rs b/edgelet/edgelet-http-workload/src/error.rs index a5f2954595f..4036f44abda 100644 --- a/edgelet/edgelet-http-workload/src/error.rs +++ b/edgelet/edgelet-http-workload/src/error.rs @@ -145,12 +145,6 @@ impl From for Error { } } -impl From for HyperError { - fn from(_error: Error) -> HyperError { - HyperError::Method - } -} - impl From for Error { fn from(error: Utf8Error) -> Error { Error { diff --git a/edgelet/edgelet-http-workload/src/lib.rs b/edgelet/edgelet-http-workload/src/lib.rs index 468ab02daf2..97085569ad5 100644 --- a/edgelet/edgelet-http-workload/src/lib.rs +++ b/edgelet/edgelet-http-workload/src/lib.rs @@ -1,11 +1,15 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] +// Remove this when clippy stops warning about old-style `allow()`, +// which can only be silenced by enabling a feature and thus requires nightly +// +// Ref: https://github.com/rust-lang-nursery/rust-clippy/issues/3159#issuecomment-420530386 +#![allow(renamed_and_removed_lints)] extern crate base64; extern crate chrono; extern crate edgelet_core; -extern crate edgelet_hsm; #[macro_use] extern crate edgelet_http; #[cfg(test)] @@ -20,7 +24,6 @@ extern crate http; extern crate hyper; #[macro_use] extern crate log; -extern crate serde; extern crate serde_json; extern crate workload; diff --git a/edgelet/edgelet-http-workload/src/server/cert/identity.rs b/edgelet/edgelet-http-workload/src/server/cert/identity.rs index acb952f111d..dcd98faba92 100644 --- a/edgelet/edgelet-http-workload/src/server/cert/identity.rs +++ b/edgelet/edgelet-http-workload/src/server/cert/identity.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. -use edgelet_http::route::{BoxFuture, Handler, Parameters}; -use futures::future; +use edgelet_http::route::{Handler, Parameters}; +use futures::{future, Future}; use http::{Request, Response}; use hyper::{Body, Error as HyperError}; @@ -12,7 +12,7 @@ impl Handler for IdentityCertHandler { &self, _req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = Response::new(Body::default()); Box::new(future::ok(response)) } diff --git a/edgelet/edgelet-http-workload/src/server/cert/server.rs b/edgelet/edgelet-http-workload/src/server/cert/server.rs index 7c9269f4d22..682661d4830 100644 --- a/edgelet/edgelet-http-workload/src/server/cert/server.rs +++ b/edgelet/edgelet-http-workload/src/server/cert/server.rs @@ -11,7 +11,7 @@ use serde_json; use edgelet_core::{ Certificate, CertificateProperties, CertificateType, CreateCertificate, KeyBytes, PrivateKey, }; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use workload::models::{ CertificateResponse, PrivateKey as PrivateKeyResponse, ServerCertificateRequest, }; @@ -31,14 +31,14 @@ impl ServerCertHandler { impl Handler for ServerCertHandler where - T: CreateCertificate + 'static + Clone, + T: CreateCertificate + 'static + Clone + Send, ::Certificate: Certificate, { fn handle( &self, req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let hsm = self.hsm.clone(); let response = params .name("name") @@ -124,8 +124,8 @@ fn compute_validity(expiration: &str) -> Result { #[cfg(test)] mod tests { - use std::rc::Rc; use std::result::Result as StdResult; + use std::sync::Arc; use chrono::offset::Utc; use chrono::Duration; @@ -138,15 +138,17 @@ mod tests { #[derive(Clone, Default)] struct TestHsm { - on_create: Option StdResult>>>, + on_create: Option< + Arc StdResult + Send + Sync>>, + >, } impl TestHsm { fn with_on_create(mut self, on_create: F) -> TestHsm where - F: Fn(&CertificateProperties) -> StdResult + 'static, + F: Fn(&CertificateProperties) -> StdResult + Send + Sync + 'static, { - self.on_create = Some(Rc::new(Box::new(on_create))); + self.on_create = Some(Arc::new(Box::new(on_create))); self } } diff --git a/edgelet/edgelet-http-workload/src/server/decrypt.rs b/edgelet/edgelet-http-workload/src/server/decrypt.rs index c01a0acbd87..e4ba35075d0 100644 --- a/edgelet/edgelet-http-workload/src/server/decrypt.rs +++ b/edgelet/edgelet-http-workload/src/server/decrypt.rs @@ -2,7 +2,7 @@ use base64; use edgelet_core::Decrypt; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use error::{Error, ErrorKind}; use failure::ResultExt; use futures::{future, Future, Stream}; @@ -25,13 +25,13 @@ impl DecryptHandler { impl Handler for DecryptHandler where - T: Decrypt + 'static + Clone, + T: Decrypt + 'static + Clone + Send, { fn handle( &self, req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let hsm = self.hsm.clone(); let response = params .name("name") diff --git a/edgelet/edgelet-http-workload/src/server/encrypt.rs b/edgelet/edgelet-http-workload/src/server/encrypt.rs index 631f2543553..629f7305f76 100644 --- a/edgelet/edgelet-http-workload/src/server/encrypt.rs +++ b/edgelet/edgelet-http-workload/src/server/encrypt.rs @@ -2,7 +2,7 @@ use base64; use edgelet_core::Encrypt; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use error::{Error, ErrorKind}; use failure::ResultExt; use futures::{future, Future, Stream}; @@ -25,13 +25,13 @@ impl EncryptHandler { impl Handler for EncryptHandler where - T: Encrypt + 'static + Clone, + T: Encrypt + 'static + Clone + Send, { fn handle( &self, req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let hsm = self.hsm.clone(); let response = params .name("name") diff --git a/edgelet/edgelet-http-workload/src/server/mod.rs b/edgelet/edgelet-http-workload/src/server/mod.rs index 07280e1b8c0..3ff1fcf50c9 100644 --- a/edgelet/edgelet-http-workload/src/server/mod.rs +++ b/edgelet/edgelet-http-workload/src/server/mod.rs @@ -6,7 +6,7 @@ mod encrypt; mod sign; mod trust_bundle; -use std::io; +use std::error::Error as StdError; use edgelet_core::{ CreateCertificate, Decrypt, Encrypt, Error as CoreError, GetTrustBundle, KeyStore, Module, @@ -14,9 +14,10 @@ use edgelet_core::{ }; use edgelet_http::authorization::Authorization; use edgelet_http::route::*; -use http::{Request, Response}; -use hyper::server::{NewService, Service}; -use hyper::{Body, Error as HyperError}; +use failure; +use futures::{future, Future}; +use hyper::service::{NewService, Service}; +use hyper::{Body, Error as HyperError, Request, Response}; use self::cert::{IdentityCertHandler, ServerCertHandler}; use self::decrypt::DecryptHandler; @@ -30,11 +31,17 @@ pub struct WorkloadService { } impl WorkloadService { - pub fn new(key_store: &K, hsm: H, runtime: &M) -> Result + // clippy bug: https://github.com/rust-lang-nursery/rust-clippy/issues/3220 + #[cfg_attr(feature = "cargo-clippy", allow(new_ret_no_self))] + pub fn new( + key_store: &K, + hsm: H, + runtime: &M, + ) -> impl Future where - K: 'static + KeyStore + Clone, - H: 'static + CreateCertificate + Decrypt + Encrypt + GetTrustBundle + Clone, - M: 'static + ModuleRuntime + Clone, + K: 'static + KeyStore + Clone + Send + Sync, + H: 'static + CreateCertificate + Decrypt + Encrypt + GetTrustBundle + Clone + Send + Sync, + M: 'static + ModuleRuntime + Clone + Send + Sync, M::Error: Into, ::Error: Into, M::Logs: Into, @@ -48,30 +55,34 @@ impl WorkloadService { get "/trust-bundle" => Authorization::new(TrustBundleHandler::new(hsm), Policy::Anonymous, runtime.clone()), ); - let inner = router.new_service()?; - let service = WorkloadService { inner }; - Ok(service) + + router + .new_service() + .map(|inner| WorkloadService { inner }) + .map_err(failure::Error::from_boxed_compat) } } impl Service for WorkloadService { - type Request = Request; - type Response = Response; + type ReqBody = Body; + type ResBody = Body; type Error = HyperError; - type Future = BoxFuture; + type Future = Box, Error = Self::Error> + Send>; - fn call(&self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { self.inner.call(req) } } impl NewService for WorkloadService { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Instance = Self; + type ReqBody = ::ReqBody; + type ResBody = ::ResBody; + type Error = ::Error; + type Service = Self; + type Future = future::FutureResult; + type InitError = Box; - fn new_service(&self) -> io::Result { - Ok(self.clone()) + fn new_service(&self) -> Self::Future { + future::ok(self.clone()) } } diff --git a/edgelet/edgelet-http-workload/src/server/sign.rs b/edgelet/edgelet-http-workload/src/server/sign.rs index 225b73535f1..17d6bca84fd 100644 --- a/edgelet/edgelet-http-workload/src/server/sign.rs +++ b/edgelet/edgelet-http-workload/src/server/sign.rs @@ -2,7 +2,7 @@ use base64; use edgelet_core::crypto::{KeyIdentity, KeyStore, Sign, Signature, SignatureAlgorithm}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use failure::ResultExt; use futures::{future, Future, Stream}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; @@ -50,13 +50,13 @@ pub fn sign( impl Handler for SignHandler where - K: 'static + KeyStore + Clone, + K: 'static + KeyStore + Clone + Send, { fn handle( &self, req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = params .name("name") .ok_or_else(|| Error::from(ErrorKind::BadParam)) @@ -97,8 +97,7 @@ where #[cfg(test)] mod tests { - use std::cell::RefCell; - use std::rc::Rc; + use std::sync::{Arc, Mutex}; use edgelet_core::crypto::MemoryKey; use edgelet_core::{Error as CoreError, ErrorKind as CoreErrorKind, KeyStore}; @@ -125,14 +124,14 @@ mod tests { #[derive(Clone, Debug)] struct TestKeyStore { key: MemoryKey, - state: Rc>, + state: Arc>, } impl TestKeyStore { pub fn new(key: MemoryKey) -> Self { TestKeyStore { key, - state: Rc::new(RefCell::new(State::new())), + state: Arc::new(Mutex::new(State::new())), } } } @@ -141,11 +140,13 @@ mod tests { type Key = MemoryKey; fn get(&self, identity: &KeyIdentity, key_name: &str) -> Result { - self.state.borrow_mut().last_id = match identity { + let state = &mut *self.state.lock().unwrap(); + state.last_id = match identity { KeyIdentity::Device => "".to_string(), KeyIdentity::Module(ref m) => m.to_string(), }; - self.state.borrow_mut().last_key_name = key_name.to_string(); + state.last_key_name = key_name.to_string(); + drop(state); Ok(self.key.clone()) } } @@ -204,8 +205,10 @@ mod tests { Ok(()) }).wait() .unwrap(); - assert_eq!(&store.state.borrow().last_id, "test"); - assert_eq!(&store.state.borrow().last_key_name, "primaryg1"); + + let state = store.state.lock().unwrap(); + assert_eq!(state.last_id, "test"); + assert_eq!(state.last_key_name, "primaryg1"); } #[test] diff --git a/edgelet/edgelet-http-workload/src/server/trust_bundle.rs b/edgelet/edgelet-http-workload/src/server/trust_bundle.rs index cedca6be771..2d1e5615b1a 100644 --- a/edgelet/edgelet-http-workload/src/server/trust_bundle.rs +++ b/edgelet/edgelet-http-workload/src/server/trust_bundle.rs @@ -3,14 +3,14 @@ use std::str; use failure::ResultExt; -use futures::future; +use futures::{future, Future}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; use http::{Request, Response, StatusCode}; use hyper::{Body, Error as HyperError}; use serde_json; use edgelet_core::{Certificate, GetTrustBundle}; -use edgelet_http::route::{BoxFuture, Handler, Parameters}; +use edgelet_http::route::{Handler, Parameters}; use workload::models::TrustBundleResponse; use error::{Error, ErrorKind}; @@ -22,7 +22,7 @@ pub struct TrustBundleHandler { impl TrustBundleHandler where - T: GetTrustBundle + 'static + Clone, + T: 'static + GetTrustBundle + Clone, { pub fn new(hsm: T) -> Self { TrustBundleHandler { hsm } @@ -31,14 +31,14 @@ where impl Handler for TrustBundleHandler where - T: GetTrustBundle + 'static, + T: 'static + GetTrustBundle + Send, ::Certificate: Certificate, { fn handle( &self, _req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = self .hsm .get_trust_bundle() diff --git a/edgelet/edgelet-http/Cargo.toml b/edgelet/edgelet-http/Cargo.toml index c98240d055a..b0ba4190010 100644 --- a/edgelet/edgelet-http/Cargo.toml +++ b/edgelet/edgelet-http/Cargo.toml @@ -11,16 +11,16 @@ failure = "0.1" failure_derive = "0.1" futures = "0.1" http = "0.1" -hyper = { version = "0.11", features = ["compat"] } -hyper-proxy = "0.4.1" -hyper-tls = "0.1" +hyper = "0.12" +hyper-proxy = "0.5" +hyper-tls = "0.3" log = "0.4" percent-encoding = "1.0" regex = "0.2" serde = "1.0" serde_json = "1.0" -tokio-core = "0.1" -tokio-io = "0.1" +tokio = "0.1.8" +typed-headers = "0.1" url = "1.7" edgelet-core = { path = "../edgelet-core" } @@ -28,21 +28,24 @@ edgelet-utils = { path = "../edgelet-utils" } systemd = { path = "../systemd" } [target.'cfg(unix)'.dependencies] -hyperlocal = "0.4" +hyperlocal = "0.6" libc = "0.2" nix = "0.11" scopeguard = "0.3.3" -tokio-uds = "0.1" +tokio-uds = "0.2" [target.'cfg(windows)'.dependencies] hyper-named-pipe = { path = "../hyper-named-pipe" } tokio-named-pipe = { path = "../tokio-named-pipe" } [dev-dependencies] -httparse = "1.2" lazy_static = "1.0" -rand = "0.4" -tokio-core = "0.1" -tempfile = "3" edgelet-test-utils = { path = "../edgelet-test-utils" } + +[target.'cfg(unix)'.dev-dependencies] +tempfile = "3" + +[target.'cfg(windows)'.dev-dependencies] +httparse = "1.2" +rand = "0.4" diff --git a/edgelet/edgelet-http/examples/identities.rs b/edgelet/edgelet-http/examples/identities.rs index b1eacf3ad66..dde759cbb72 100644 --- a/edgelet/edgelet-http/examples/identities.rs +++ b/edgelet/edgelet-http/examples/identities.rs @@ -5,18 +5,20 @@ extern crate edgelet_http; extern crate futures; extern crate http; extern crate hyper; -extern crate tokio_core; +extern crate tokio; -use edgelet_http::route::{BoxFuture, Builder, Parameters, Router}; +use edgelet_http::route::{Builder, Parameters, Router}; use edgelet_http::HyperExt; -use futures::future; +use futures::{future, Future}; use http::header::CONTENT_TYPE; use http::{Request, Response, StatusCode}; -use hyper::server::Http; +use hyper::server::conn::Http; use hyper::{Body, Error as HyperError}; -use tokio_core::reactor::Core; -fn index(_req: Request, _params: Parameters) -> BoxFuture, HyperError> { +fn index( + _req: Request, + _params: Parameters, +) -> Box, Error = HyperError> + Send> { let response = Response::builder() .status(StatusCode::OK) .header(CONTENT_TYPE, "text/plain") @@ -28,7 +30,7 @@ fn index(_req: Request, _params: Parameters) -> BoxFuture, fn identities_list( _req: Request, _params: Parameters, -) -> BoxFuture, HyperError> { +) -> Box, Error = HyperError> + Send> { let response = Response::builder() .status(StatusCode::OK) .header(CONTENT_TYPE, "application/json") @@ -40,7 +42,7 @@ fn identities_list( fn identities_update( _req: Request, params: Parameters, -) -> BoxFuture, HyperError> { +) -> Box, Error = HyperError> + Send> { let response = params .name("name") .map(|name| { @@ -62,7 +64,7 @@ fn identities_update( fn identities_delete( _req: Request, _params: Parameters, -) -> BoxFuture, HyperError> { +) -> Box, Error = HyperError> + Send> { let response = Response::builder() .status(StatusCode::BAD_REQUEST) .body(Body::default()) @@ -71,8 +73,6 @@ fn identities_delete( } fn main() { - let mut core = Core::new().unwrap(); - let handle = core.handle(); let router = router!( get "/" => index, get "/identities" => identities_list, @@ -83,6 +83,10 @@ fn main() { let addr = "tcp://0.0.0.0:8080".parse().unwrap(); println!("Starting server on {}", addr); - let run = Http::new().bind_handle(addr, handle, router).unwrap().run(); - core.run(run).unwrap(); + let run = Http::new().bind_url(addr, router).unwrap().run(); + + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(run) + .unwrap(); } diff --git a/edgelet/edgelet-http/src/authorization.rs b/edgelet/edgelet-http/src/authorization.rs index 737560d5b39..5472cce54f4 100644 --- a/edgelet/edgelet-http/src/authorization.rs +++ b/edgelet/edgelet-http/src/authorization.rs @@ -1,14 +1,12 @@ // Copyright (c) Microsoft. All rights reserved. -use edgelet_core::{ - pid::Pid, Authorization as CoreAuth, Error as CoreError, Module, ModuleRuntime, Policy, -}; +use edgelet_core::pid::Pid; +use edgelet_core::{Authorization as CoreAuth, Error as CoreError, Module, ModuleRuntime, Policy}; use error::{Error, ErrorKind}; -use futures::{future, future::Either, Future}; -use http::{Request, Response}; -use hyper::{Body, Error as HyperError}; -use route::{BoxFuture, Handler, Parameters}; -use std::rc::Rc; +use futures::{future, Future}; +use hyper::{self, Body, Request, Response}; +use route::{Handler, Parameters}; +use std::sync::Arc; use IntoResponse; pub struct Authorization @@ -17,7 +15,7 @@ where M: 'static + ModuleRuntime, { auth: CoreAuth, - inner: Rc, + inner: Arc, } impl Authorization @@ -30,15 +28,15 @@ where pub fn new(inner: H, policy: Policy, runtime: M) -> Self { Authorization { auth: CoreAuth::new(runtime, policy), - inner: Rc::new(inner), + inner: Arc::new(inner), } } } impl Handler for Authorization where - H: Handler, - M: 'static + ModuleRuntime, + H: Handler + Sync, + M: 'static + ModuleRuntime + Send, M::Error: Into, ::Error: Into, { @@ -46,7 +44,7 @@ where &self, req: Request, params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = hyper::Error> + Send> { let (name, pid) = ( params.name("name").map(|n| n.to_string()), req.extensions() @@ -62,9 +60,9 @@ where .map_err(Error::from) .and_then(move |authorized| { if authorized { - Either::A(inner.handle(req, params).map_err(Error::from)) + future::Either::A(inner.handle(req, params).map_err(Error::from)) } else { - Either::B(future::err(Error::from(ErrorKind::NotFound))) + future::Either::B(future::err(Error::from(ErrorKind::NotFound))) } }).or_else(|e| future::ok(e.into_response())); @@ -74,12 +72,13 @@ where #[cfg(test)] mod tests { - use std::time::Duration; use super::*; use edgelet_core::{LogOptions, ModuleRegistry, ModuleRuntimeState, ModuleSpec, SystemInfo}; - use futures::{future::FutureResult, stream::Empty, Stream}; + use futures::future::FutureResult; + use futures::stream::Empty; + use futures::Stream; use http::{Request, Response, StatusCode}; use hyper::{Body, Error as HyperError}; @@ -168,7 +167,7 @@ mod tests { &self, _req: Request, _params: Parameters, - ) -> BoxFuture, HyperError> { + ) -> Box, Error = HyperError> + Send> { let response = Response::builder() .status(StatusCode::OK) .body("from TestHandler".into()) diff --git a/edgelet/edgelet-http/src/client.rs b/edgelet/edgelet-http/src/client.rs index b7bcf894b52..510f778f1d9 100644 --- a/edgelet/edgelet-http/src/client.rs +++ b/edgelet/edgelet-http/src/client.rs @@ -1,17 +1,18 @@ // Copyright (c) Microsoft. All rights reserved. use std::collections::HashMap; -use std::rc::Rc; +use std::sync::Arc; use chrono::{DateTime, Duration, Utc}; use futures::future::{self, Either}; -use futures::{Future, Stream}; -use hyper::client::Service; -use hyper::header::{Authorization, ContentLength, ContentType, IfMatch, UserAgent}; -use hyper::{Error as HyperError, Method, Request, Response, Uri}; -use serde::{de::DeserializeOwned, Serialize}; +use futures::{Future, IntoFuture, Stream}; +use hyper::{self, Body, Error as HyperError, Method, Request, Response}; +use serde::de::DeserializeOwned; +use serde::Serialize; use serde_json; -use url::{form_urlencoded::Serializer as UrlSerializer, Url}; +use typed_headers::{http, mime, ContentLength, ContentType, HeaderMapExt}; +use url::form_urlencoded::Serializer as UrlSerializer; +use url::Url; use error::Error; @@ -20,67 +21,96 @@ pub trait TokenSource { fn get(&self, expiry: &DateTime) -> Result; } -pub struct Client +pub trait ClientImpl: Send + Sync { + type Response: Future, Error = hyper::Error> + Send; + + fn call(&self, req: Request) -> Self::Response; +} + +impl ClientImpl for hyper::Client where - S: 'static + Service, - T: TokenSource + Clone, + C: hyper::client::connect::Connect + Sync + 'static, + ::Transport: 'static, + ::Future: 'static, +{ + type Response = hyper::client::ResponseFuture; + + fn call(&self, req: Request) -> Self::Response { + self.request(req) + } +} + +impl ClientImpl for F +where + F: Fn(Request) -> R + Send + Sync, + R: IntoFuture, Error = hyper::Error>, + ::Future: Send, { - service: Rc, + type Response = ::Future; + + fn call(&self, req: Request) -> Self::Response { + (self)(req).into_future() + } +} + +pub struct Client { + inner: Arc, token_source: Option, api_version: String, host_name: Url, user_agent: Option, } -impl Client +impl Client where - S: 'static + Service, + C: ClientImpl, T: TokenSource + Clone, T::Error: Into, { pub fn new( - service: S, + inner: C, token_source: Option, api_version: &str, host_name: Url, - ) -> Result, Error> { + ) -> Result { let client = Client { - service: Rc::new(service), + inner: Arc::new(inner), token_source, api_version: ensure_not_empty!(api_version).to_string(), host_name, user_agent: None, }; + Ok(client) } - pub fn with_token_source(mut self, source: T) -> Client { + pub fn with_token_source(mut self, source: T) -> Self { self.token_source = Some(source); self } - pub fn with_user_agent(mut self, user_agent: &str) -> Client { + pub fn with_user_agent(mut self, user_agent: &str) -> Self { self.user_agent = Some(user_agent.to_string()); self } - pub fn client(&self) -> &S { - self.service.as_ref() + pub fn inner(&self) -> &C { + &self.inner } pub fn api_version(&self) -> &str { &self.api_version } - pub fn user_agent(&self) -> Option<&String> { - self.user_agent.as_ref() + pub fn user_agent(&self) -> Option<&str> { + self.user_agent.as_ref().map(String::as_str) } pub fn host_name(&self) -> &Url { &self.host_name } - fn add_sas_token(&self, req: &mut Request, path: &str) -> Result<(), Error> { + fn add_sas_token(&self, req: &mut Request, path: &str) -> Result<(), Error> { if let Some(ref source) = self.token_source { let token_duration = Duration::hours(1); let expiry = Utc::now() + token_duration; @@ -90,8 +120,10 @@ where req.method(), path, ); - req.headers_mut() - .set(Authorization(format!("SharedAccessSignature {}", token))); + req.headers_mut().append( + http::header::AUTHORIZATION, + format!("SharedAccessSignature {}", token).parse().unwrap(), + ); } else { debug!("Empty token source for request {} {}", req.method(), path); } @@ -125,48 +157,47 @@ where .join(&format!("{}?{}", path, query)) .map_err(Error::from) .and_then(|url| { - // NOTE: 'expect' here should be OK, because this is a type - // conversion from url::Url to hyper::Uri and not really a URL - // parse operation. At this point the URL has already been parsed - // and is known to be good. - let mut req = Request::new(method, - url.as_str().parse::().expect("Unexpected Url to Uri conversion failure") - ); + let mut req = Request::builder(); + req.method(method).uri(url.as_str()); // add user agent header if let Some(ref user_agent) = self.user_agent { - req.headers_mut().set(UserAgent::new(user_agent.clone())); + req.header(http::header::USER_AGENT, &**user_agent); } - // add sas token - self.add_sas_token(&mut req, path)?; - // add an `If-Match: "*"` header if we've been asked to if add_if_match { - req.headers_mut().set(IfMatch::Any); + req.header(http::header::IF_MATCH, "*"); } // add request body if there is any - if let Some(body) = body { + let mut req = if let Some(body) = body { let serialized = serde_json::to_string(&body)?; - req.headers_mut().set(ContentType::json()); - req.headers_mut().set(ContentLength(serialized.len() as u64)); - - req.set_body(serialized); + let serialized_len = serialized.len(); + let mut req = req.body(Body::from(serialized))?; + req.headers_mut().typed_insert(&ContentType(mime::APPLICATION_JSON)); + req.headers_mut().typed_insert(&ContentLength(serialized_len as u64)); + req } + else { + req.body(Body::empty())? + }; + + // add sas token + self.add_sas_token(&mut req, path)?; Ok(req) }) .map(|req| { - let res = self.service - .call(req) + let res = + self.inner.call(req) .map_err(|e| { error!("{:?}", e); Error::from(e) }) .and_then(|resp| { - let status = resp.status(); - resp.body() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body .concat2() .and_then(move |body| Ok((status, body))) - .map_err(Error::from) + .map_err(>::from) }) .and_then(|(status, body)| { if status.is_success() { @@ -191,18 +222,17 @@ where } } -impl Clone for Client +impl Clone for Client where - S: 'static + Service, T: TokenSource + Clone, { fn clone(&self) -> Self { Client { - service: self.service.clone(), - token_source: self.token_source.as_ref().cloned(), + inner: self.inner.clone(), + token_source: self.token_source.clone(), api_version: self.api_version.clone(), host_name: self.host_name.clone(), - user_agent: self.user_agent.as_ref().cloned(), + user_agent: self.user_agent.clone(), } } } @@ -216,11 +246,9 @@ mod tests { use chrono::{DateTime, Utc}; use futures::future; - use hyper::client::Client as HyperClient; - use hyper::header::{Authorization, ContentType, UserAgent}; - use hyper::server::service_fn; - use hyper::{Request, Response, StatusCode}; - use tokio_core::reactor::Core; + use hyper::{Client as HyperClient, Request, Response}; + use tokio; + use typed_headers::{mime, ContentType}; use url::form_urlencoded::parse as parse_query; use error::ErrorKind; @@ -252,8 +280,7 @@ mod tests { #[test] fn empty_api_version_fails() { - let core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let token_source: Option = None; match Client::new( hyper_client, @@ -272,8 +299,7 @@ mod tests { #[test] fn white_space_api_version_fails() { - let core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let token_source: Option = None; match Client::new( hyper_client, @@ -292,51 +318,50 @@ mod tests { #[test] fn request_adds_api_version() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let response = r#""response""#.to_string(); + let response = r#""response""#; let token_source: Option = None; - let handler = move |req: Request| { - assert_eq!(req.path(), "/boo"); - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(req.uri().path(), "/boo"); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); // check that the query has api version_ - let query_map: HashMap = parse_query(req.query().unwrap().as_bytes()) - .into_owned() - .collect(); + let query_map: HashMap = + parse_query(req.uri().query().unwrap().as_bytes()) + .into_owned() + .collect(); assert_eq!(query_map.get("api-version"), Some(&api_version.to_string())); - Box::new(future::ok( - Response::new() - .with_status(StatusCode::Ok) - .with_body(response.clone().into_bytes()), - )) + future::ok(Response::new(response.into())) }; - let client = - Client::new(service_fn(handler), token_source, api_version, host_name).unwrap(); + let client = Client::new(handler, token_source, api_version, host_name).unwrap(); + + let task = client.request::(Method::GET, "/boo", None, None, false); - let task = client.request::(Method::Get, "/boo", None, None, false); - let _result: Option = core.run(task).unwrap(); + let _result: Option = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn request_adds_api_version_with_other_query_params() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let response = r#""response""#.to_string(); + let response = r#""response""#; let token_source: Option = None; - let handler = move |req: Request| { - assert_eq!(req.path(), "/boo"); - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(req.uri().path(), "/boo"); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); // check that the query has api version - let query_map: HashMap = parse_query(req.query().unwrap().as_bytes()) - .into_owned() - .collect(); + let query_map: HashMap = + parse_query(req.uri().query().unwrap().as_bytes()) + .into_owned() + .collect(); assert_eq!(query_map.get("api-version"), Some(&api_version.to_string())); assert_eq!(query_map.get("k1"), Some(&"v1".to_string())); assert_eq!( @@ -344,194 +369,205 @@ mod tests { Some(&"this value has spaces and 🐮🐮🐮".to_string()) ); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_body(response.clone().into_bytes())) + Ok(Response::new(response.into())) }; - let client = - Client::new(service_fn(handler), token_source, api_version, host_name).unwrap(); + let client = Client::new(handler, token_source, api_version, host_name).unwrap(); let mut query = HashMap::new(); query.insert("k1", "v1"); query.insert("k2", "this value has spaces and 🐮🐮🐮"); - let task = client.request::(Method::Get, "/boo", Some(query), None, false); - let _result: String = core.run(task).unwrap().unwrap(); + let task = client.request::(Method::GET, "/boo", Some(query), None, false); + + let _result: String = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap() + .unwrap(); } #[test] fn request_adds_user_agent() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let user_agent = "edgelet/request/test"; let host_name = Url::parse("http://localhost").unwrap(); - let response = r#""response""#.to_string(); + let response = r#""response""#; let token_source: Option = None; - let handler = move |req: Request| { + let handler = move |req: Request| { assert_eq!( user_agent, - &req.headers().get::().unwrap().to_string() + &*req.headers().get(hyper::header::USER_AGENT).unwrap(), ); - assert_eq!(None, req.headers().get::()); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_body(response.clone().into_bytes())) + Ok(Response::new(response.into())) }; - let client = Client::new(service_fn(handler), token_source, api_version, host_name) + let client = Client::new(handler, token_source, api_version, host_name) .unwrap() .with_user_agent(user_agent); - let task = client.request::(Method::Get, "/boo", None, None, false); - let _result: String = core.run(task).unwrap().unwrap(); + let task = client.request::(Method::GET, "/boo", None, None, false); + + let _result: String = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap() + .unwrap(); } #[test] fn request_adds_sas_token() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let sas_token = "super_secret_password_y'all"; let host_name = Url::parse("http://localhost").unwrap(); - let response = r#""response""#.to_string(); - - let handler = move |req: Request| { - let sas_header = &req - .headers() - .get::>() - .unwrap() - .to_string(); + let response = r#""response""#; + + let handler = move |req: Request| { + let sas_header = req.headers().get(hyper::header::AUTHORIZATION).unwrap(); let expected_sas = format!("SharedAccessSignature {}", sas_token); - assert_eq!(&expected_sas, sas_header); - assert_eq!(None, req.headers().get::()); + assert_eq!(expected_sas, *sas_header); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_body(response.clone().into_bytes())) + Ok(Response::new(response.into())) }; let token_source: Option = Some(StaticTokenSource::new(sas_token.to_string())); - let client = - Client::new(service_fn(handler), token_source, api_version, host_name).unwrap(); + let client = Client::new(handler, token_source, api_version, host_name).unwrap(); + + let task = client.request::(Method::GET, "/boo", None, None, false); - let task = client.request::(Method::Get, "/boo", None, None, false); - let _result: String = core.run(task).unwrap().unwrap(); + let _result: String = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap() + .unwrap(); } #[test] fn request_adds_if_match_header() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let response = r#""response""#.to_string(); + let response = r#""response""#; let token_source: Option = None; - let handler = move |req: Request| { - assert_eq!(Some(&IfMatch::Any), req.headers().get::()); + let handler = move |req: Request| { + assert_eq!( + Some("*").map(AsRef::as_ref), + req.headers() + .get(hyper::header::IF_MATCH) + .map(AsRef::as_ref) + ); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body(response.clone().into_bytes())) + let mut response = Response::new(response.into()); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }; - let client = - Client::new(service_fn(handler), token_source, api_version, host_name).unwrap(); + let client = Client::new(handler, token_source, api_version, host_name).unwrap(); + + let task = client.request::(Method::GET, "/boo", None, None, true); - let task = client.request::(Method::Get, "/boo", None, None, true); - let _result: String = core.run(task).unwrap().unwrap(); + let _result: String = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap() + .unwrap(); } #[test] fn request_adds_body() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); + let response = r#""response""#; let token_source: Option = None; - let handler = move |req: Request| { - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - req.body() + req.into_body() .concat2() .and_then(|req_body| { str::from_utf8(&req_body) .map(move |req_body| { assert_eq!("\"Here be dragons\"".to_string(), req_body) }).map_err(|e| panic!("Error: {:?}", e)) - }).and_then(|_| { - let response = r#""response""#.to_string(); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_body(response.clone().into_bytes())) - }) + }).and_then(|_| Ok(Response::new(response.into()))) }; - let client = - Client::new(service_fn(handler), token_source, api_version, host_name).unwrap(); + let client = Client::new(handler, token_source, api_version, host_name).unwrap(); let task = client.request::( - Method::Post, + Method::POST, "/boo", None, Some("Here be dragons".to_string()), false, ); - let _result: String = core.run(task).unwrap().unwrap(); + + let _result: String = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap() + .unwrap(); } #[test] fn request_can_return_empty_response() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); let token_source: Option = None; - let handler = move |req: Request| { - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - req.body() + req.into_body() .concat2() .and_then(|req_body| { str::from_utf8(&req_body) .map(move |req_body| { assert_eq!("\"Here be dragons\"".to_string(), req_body) }).map_err(|e| panic!("Error: {:?}", e)) - }).and_then(|_| Ok(Response::new().with_status(StatusCode::Ok))) + }).and_then(|_| Ok(Response::new(Body::empty()))) }; - let client = - Client::new(service_fn(handler), token_source, api_version, host_name).unwrap(); + let client = Client::new(handler, token_source, api_version, host_name).unwrap(); let task = client.request::( - Method::Post, + Method::POST, "/boo", None, Some("Here be dragons".to_string()), false, ); - let result: Option = core.run(task).unwrap(); + + let result: Option = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); assert_eq!(result, None); } #[test] fn request_returns_response() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let response = r#""response""#.to_string(); + let response = r#""response""#; let token_source: Option = None; - let handler = move |req: Request| { - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_body(response.clone().into_bytes())) + Ok(Response::new(response.into())) }; - let client = - Client::new(service_fn(handler), token_source, api_version, host_name).unwrap(); + let client = Client::new(handler, token_source, api_version, host_name).unwrap(); - let task = client.request::(Method::Get, "/boo", None, None, false); - let result: String = core.run(task).unwrap().unwrap(); + let task = client.request::(Method::GET, "/boo", None, None, false); + let result: String = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap() + .unwrap(); assert_eq!(result, "response"); } } diff --git a/edgelet/edgelet-http/src/compat.rs b/edgelet/edgelet-http/src/compat.rs deleted file mode 100644 index 5ab3c9a5d9d..00000000000 --- a/edgelet/edgelet-http/src/compat.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. - -//! Wrappers to build compatibility with the `http` crate. - -use futures::{Future, Poll}; -use http; -use hyper::server::Service; -use hyper::{Body, Error, Request, Response}; - -/// Wraps a `Future` returning an `http::Response` into -/// a `Future` returning a `hyper::server::Response`. -#[derive(Debug)] -pub(crate) struct CompatFuture { - future: F, -} - -impl Future for CompatFuture -where - F: Future, Error = Error>, -{ - type Item = Response; - type Error = Error; - - fn poll(&mut self) -> Poll { - self.future.poll().map(|a| a.map(|res| res.into())) - } -} - -/// Wraps a `Service` taking an `http::Request` and returning -/// an `http::Response` into a `Service` taking a `hyper::server::Request`, -/// and returning a `hyper::server::Response`. -#[derive(Debug)] -pub(crate) struct CompatService { - service: S, -} - -pub(crate) fn service(service: S) -> CompatService { - CompatService { service } -} - -impl Service for CompatService -where - S: Service, Response = http::Response, Error = Error>, -{ - type Request = Request; - type Response = Response; - type Error = Error; - type Future = CompatFuture; - - fn call(&self, req: Self::Request) -> Self::Future { - CompatFuture { - future: self.service.call(req.into()), - } - } -} diff --git a/edgelet/edgelet-http/src/error.rs b/edgelet/edgelet-http/src/error.rs index 0a9a4c6a259..f7204b71dd8 100644 --- a/edgelet/edgelet-http/src/error.rs +++ b/edgelet/edgelet-http/src/error.rs @@ -8,8 +8,7 @@ use std::str; use edgelet_core::{Error as CoreError, ErrorKind as CoreErrorKind}; use failure::{Backtrace, Context, Fail}; use http::header::{CONTENT_LENGTH, CONTENT_TYPE}; -use http::{Response, StatusCode}; -use hyper::error::UriError; +use http::{self, Response, StatusCode}; use hyper::{Body, Error as HyperError, StatusCode as HyperStatusCode}; #[cfg(windows)] use hyper_named_pipe::Error as PipeError; @@ -35,6 +34,8 @@ pub enum ErrorKind { Io, #[fail(display = "Service error: [{}] {}", _0, _1)] ServiceError(HyperStatusCode, String), + #[fail(display = "Http error")] + Http, #[fail(display = "Hyper error")] Hyper, #[fail(display = "Utils error")] @@ -103,17 +104,19 @@ impl From> for Error { } } -impl From for Error { - fn from(error: HyperError) -> Error { +impl From for Error { + fn from(error: http::Error) -> Error { Error { - inner: error.context(ErrorKind::Hyper), + inner: error.context(ErrorKind::Http), } } } -impl From for HyperError { - fn from(_error: Error) -> HyperError { - HyperError::Method +impl From for Error { + fn from(error: HyperError) -> Error { + Error { + inner: error.context(ErrorKind::Hyper), + } } } @@ -251,11 +254,3 @@ impl From for Error { } } } - -impl From for Error { - fn from(error: UriError) -> Error { - Error { - inner: error.context(ErrorKind::Parse), - } - } -} diff --git a/edgelet/edgelet-http/src/lib.rs b/edgelet/edgelet-http/src/lib.rs index dfc749c35d3..f3cdc61883e 100644 --- a/edgelet/edgelet-http/src/lib.rs +++ b/edgelet/edgelet-http/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] extern crate bytes; extern crate chrono; @@ -19,9 +19,6 @@ extern crate hyper_tls; #[cfg(unix)] extern crate hyperlocal; #[cfg(target_os = "linux")] -#[cfg(test)] -#[macro_use] -extern crate lazy_static; #[cfg(unix)] extern crate libc; #[macro_use] @@ -37,15 +34,15 @@ extern crate serde; #[macro_use] extern crate serde_json; extern crate systemd; +#[cfg(unix)] #[cfg(test)] extern crate tempfile; -#[macro_use] -extern crate tokio_core; -extern crate tokio_io; +extern crate tokio; #[cfg(windows)] extern crate tokio_named_pipe; #[cfg(unix)] extern crate tokio_uds; +extern crate typed_headers; extern crate url; #[macro_use] @@ -57,22 +54,21 @@ use std::net; use std::net::ToSocketAddrs; #[cfg(unix)] use std::os::unix::io::FromRawFd; +use std::sync::Arc; use futures::{future, Future, Poll, Stream}; -use http::{Request, Response}; -use hyper::server::{Http, NewService}; -use hyper::{Body, Error as HyperError}; +use hyper::server::conn::Http; +use hyper::service::{NewService, Service}; +use hyper::{Body, Error as HyperError, Response}; #[cfg(unix)] use systemd::Socket; -use tokio_core::net::TcpListener; -use tokio_core::reactor::Handle; +use tokio::net::TcpListener; #[cfg(unix)] use tokio_uds::UnixListener; use url::Url; pub mod authorization; pub mod client; -mod compat; pub mod error; pub mod logging; mod pid; @@ -106,33 +102,30 @@ impl IntoResponse for Response { } } -pub struct Run(Box + 'static>); +pub struct Run(Box + Send + 'static>); impl Future for Run { type Item = (); - type Error = HyperError; + type Error = failure::Error; - fn poll(&mut self) -> Poll<(), Self::Error> { + fn poll(&mut self) -> Poll { self.0.poll() } } -pub struct Server -where - B: Stream, - B::Item: AsRef<[u8]>, -{ - protocol: Http, +pub struct Server { + protocol: Http, new_service: S, - handle: Handle, incoming: Incoming, } -impl Server +impl Server where - S: NewService, Response = Response, Error = HyperError> + 'static, - B: Stream + 'static, - B::Item: AsRef<[u8]>, + S: NewService + Send + 'static, + ::Future: Send, + ::Service: Send, + ::InitError: std::fmt::Display, + <::Service as Service>::Future: Send, { pub fn run(self) -> Run { self.run_until(future::empty()) @@ -140,25 +133,42 @@ where pub fn run_until(self, shutdown_signal: F) -> Run where - F: Future + 'static, + F: Future + Send + 'static, { let Server { protocol, new_service, - handle, incoming, } = self; + let protocol = Arc::new(protocol); + let srv = incoming.for_each(move |(socket, addr)| { + let protocol = protocol.clone(); + debug!("accepted new connection ({})", addr); let pid = socket.pid()?; - let srv = new_service.new_service()?; - let service = PidService::new(pid, srv); - let fut = protocol - .serve_connection(socket, self::compat::service(service)) - .map(|_| ()) - .map_err(move |err| error!("server connection error: ({}) {}", addr, err)); - handle.spawn(fut); + let fut = new_service + .new_service() + .then(move |srv| match srv { + Ok(srv) => Ok((srv, addr)), + Err(err) => { + error!("server connection error: ({}) {}", addr, err); + Err(()) + } + }).and_then(move |(srv, addr)| { + let service = PidService::new(pid, srv); + protocol + .serve_connection(socket, service) + .then(move |result| match result { + Ok(_) => Ok(()), + Err(err) => { + error!("server connection error: ({}) {}", addr, err); + Err(()) + } + }) + }); + tokio::spawn(fut); Ok(()) }); @@ -179,30 +189,16 @@ where } } -pub trait HyperExt + 'static> { - fn bind_handle( - &self, - url: Url, - handle: Handle, - new_service: S, - ) -> Result, Error> +pub trait HyperExt { + fn bind_url(&self, url: Url, new_service: S) -> Result, Error> where - S: NewService, Response = Response, Error = HyperError> - + 'static, - Bd: Stream; + S: NewService + 'static; } -impl + 'static> HyperExt for Http { - fn bind_handle( - &self, - url: Url, - handle: Handle, - new_service: S, - ) -> Result, Error> +impl HyperExt for Http { + fn bind_url(&self, url: Url, new_service: S) -> Result, Error> where - S: NewService, Response = Response, Error = HyperError> - + 'static, - Bd: Stream, + S: NewService + 'static, { let incoming = match url.scheme() { HTTP_SCHEME | TCP_SCHEME => { @@ -210,13 +206,13 @@ impl + 'static> HyperExt for Http { io::Error::new(io::ErrorKind::Other, format!("Invalid url: {}", url)) })?; - let listener = TcpListener::bind(&addr, &handle)?; + let listener = TcpListener::bind(&addr)?; Incoming::Tcp(listener) } #[cfg(unix)] UNIX_SCHEME => { let path = url.path(); - unix::listener(path, &handle)? + unix::listener(path)? } #[cfg(unix)] FD_SCHEME => { @@ -230,13 +226,13 @@ impl + 'static> HyperExt for Http { .or_else(|_| systemd::listener_name(host))?; match socket { - Socket::Inet(fd, addr) => { + Socket::Inet(fd, _addr) => { let l = unsafe { net::TcpListener::from_raw_fd(fd) }; - Incoming::Tcp(TcpListener::from_listener(l, &addr, &handle)?) + Incoming::Tcp(TcpListener::from_std(l, &Default::default())?) } Socket::Unix(fd) => { let l = unsafe { ::std::os::unix::net::UnixListener::from_raw_fd(fd) }; - Incoming::Unix(UnixListener::from_listener(l, &handle)?) + Incoming::Unix(UnixListener::from_std(l, &Default::default())?) } _ => Err(Error::from(ErrorKind::InvalidUri(url.to_string())))?, } @@ -247,117 +243,7 @@ impl + 'static> HyperExt for Http { Ok(Server { protocol: self.clone(), new_service, - handle, incoming, }) } } - -#[cfg(target_os = "linux")] -#[cfg(test)] -mod linux_tests { - use super::*; - - use std::env; - use std::sync::{Mutex, MutexGuard}; - - use http::StatusCode; - use hyper::server::Service; - use nix::sys::socket::{self, AddressFamily, SockType}; - use nix::unistd::{self, getpid}; - use systemd::Fd; - use tokio_core::reactor::Core; - - lazy_static! { - static ref LOCK: Mutex<()> = Mutex::new(()); - } - - const ENV_FDS: &str = "LISTEN_FDS"; - const ENV_PID: &str = "LISTEN_PID"; - - #[derive(Clone)] - struct TestService { - status_code: StatusCode, - error: bool, - } - - impl Service for TestService { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Future = Box>; - - fn call(&self, _req: Self::Request) -> Self::Future { - Box::new(if self.error { - future::err(HyperError::TooLarge) - } else { - future::ok( - Response::builder() - .status(self.status_code) - .body(Body::default()) - .unwrap(), - ) - }) - } - } - - fn lock_env<'a>() -> MutexGuard<'a, ()> { - LOCK.lock().unwrap() - } - - fn set_current_pid() { - let pid = getpid(); - env::set_var(ENV_PID, format!("{}", pid)); - } - - fn create_fd(family: AddressFamily, type_: SockType) -> Fd { - let fd = socket::socket(family, type_, socket::SockFlag::empty(), None).unwrap(); - fd - } - - #[test] - fn test_fd_ok() { - let core = Core::new().unwrap(); - let _l = lock_env(); - set_current_pid(); - let fd = create_fd(AddressFamily::Unix, SockType::Stream); - - // set the env var so that it contains the created fd - env::set_var(ENV_FDS, format!("{}", fd - 3 + 1)); - - let url = Url::parse(&format!("fd://{}", fd - 3)).unwrap(); - let run = Http::new().bind_handle(url, core.handle(), move || { - let service = TestService { - status_code: StatusCode::OK, - error: false, - }; - Ok(service) - }); - - unistd::close(fd).unwrap(); - assert!(run.is_ok()); - } - - #[test] - fn test_fd_err() { - let core = Core::new().unwrap(); - let _l = lock_env(); - set_current_pid(); - let fd = create_fd(AddressFamily::Unix, SockType::Stream); - - // set the env var so that it contains the created fd - env::set_var(ENV_FDS, format!("{}", fd - 3 + 1)); - - let url = Url::parse("fd://100").unwrap(); - let run = Http::new().bind_handle(url, core.handle(), move || { - let service = TestService { - status_code: StatusCode::OK, - error: false, - }; - Ok(service) - }); - - unistd::close(fd).unwrap(); - assert!(run.is_err()); - } -} diff --git a/edgelet/edgelet-http/src/logging.rs b/edgelet/edgelet-http/src/logging.rs index 941c4ccda11..0341592239f 100644 --- a/edgelet/edgelet-http/src/logging.rs +++ b/edgelet/edgelet-http/src/logging.rs @@ -1,15 +1,15 @@ // Copyright (c) Microsoft. All rights reserved. #![allow(deprecated)] -use std::io; +use std::error::Error as StdError; use chrono::prelude::*; use edgelet_core::pid::Pid; +use futures::future; use futures::prelude::*; use http::header::{CONTENT_LENGTH, USER_AGENT}; -use http::{Request, Response}; -use hyper::server::{NewService, Service}; -use hyper::{Body, Error as HyperError}; +use hyper::service::{NewService, Service}; +use hyper::{Body, Request, Response}; #[derive(Clone)] pub struct LoggingService { @@ -68,14 +68,14 @@ where impl Service for LoggingService where - T: Service, Response = Response>, + T: Service, { - type Request = T::Request; - type Response = T::Response; + type ReqBody = T::ReqBody; + type ResBody = T::ResBody; type Error = T::Error; type Future = ResponseFuture; - fn call(&self, req: Self::Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let uri = req .uri() .query() @@ -103,15 +103,16 @@ where impl NewService for LoggingService where - T: Clone + Service, Response = Response, Error = HyperError>, - T::Future: 'static, + T: Clone + Service, { - type Request = T::Request; - type Response = Response; - type Error = HyperError; - type Instance = Self; + type ReqBody = ::ReqBody; + type ResBody = ::ResBody; + type Error = ::Error; + type Service = Self; + type Future = future::FutureResult; + type InitError = Box; - fn new_service(&self) -> io::Result { - Ok(self.clone()) + fn new_service(&self) -> Self::Future { + future::ok(self.clone()) } } diff --git a/edgelet/edgelet-http/src/pid.rs b/edgelet/edgelet-http/src/pid.rs index e3854ba9778..ae66c582d93 100644 --- a/edgelet/edgelet-http/src/pid.rs +++ b/edgelet/edgelet-http/src/pid.rs @@ -1,42 +1,34 @@ // Copyright (c) Microsoft. All rights reserved. -use std::marker::PhantomData; - use edgelet_core::pid::Pid; use futures::prelude::*; -use http::{Request, Response}; -use hyper::server::Service; -use hyper::{Body, Error as HyperError}; +use hyper::service::Service; +use hyper::{Body, Error as HyperError, Request}; #[derive(Clone)] -pub struct PidService { +pub struct PidService { pid: Pid, inner: T, - phantom: PhantomData, } -impl PidService { - pub fn new(pid: Pid, inner: T) -> PidService { - PidService { - pid, - inner, - phantom: PhantomData, - } +impl PidService { + pub fn new(pid: Pid, inner: T) -> PidService { + PidService { pid, inner } } } -impl Service for PidService +impl Service for PidService where - T: Service, Response = Response>, - B: Stream + 'static, - B::Item: AsRef<[u8]>, + T: Service, + ::ResBody: Stream + 'static, + <::ResBody as Stream>::Item: AsRef<[u8]>, { - type Request = T::Request; - type Response = T::Response; + type ReqBody = T::ReqBody; + type ResBody = T::ResBody; type Error = T::Error; type Future = T::Future; - fn call(&self, req: Self::Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let mut req = req; req.extensions_mut().insert(self.pid.clone()); self.inner.call(req) diff --git a/edgelet/edgelet-http/src/route/mod.rs b/edgelet/edgelet-http/src/route/mod.rs index cdd65e66e8d..723115f297b 100644 --- a/edgelet/edgelet-http/src/route/mod.rs +++ b/edgelet/edgelet-http/src/route/mod.rs @@ -4,28 +4,37 @@ /// with some changes to improve usability of the captured parameters /// when using regex based routes. use std::clone::Clone; -use std::io; +use std::error::Error as StdError; use std::sync::Arc; use futures::{future, Future}; -use http::{Method, Request, Response, StatusCode}; -use hyper::server::{NewService, Service}; -use hyper::{Body, Error as HyperError}; +use hyper::service::{NewService, Service}; +use hyper::{self, Body, Method, Request, Response, StatusCode}; pub mod macros; mod regex; pub type BoxFuture = Box>; -pub trait Handler

: 'static { - fn handle(&self, req: Request, params: P) -> BoxFuture, HyperError>; +pub trait Handler

: 'static + Send { + fn handle( + &self, + req: Request, + params: P, + ) -> Box, Error = hyper::Error> + Send>; } impl Handler

for F where - F: 'static + Fn(Request, P) -> BoxFuture, HyperError>, + F: 'static + + Fn(Request, P) -> Box, Error = hyper::Error> + Send> + + Send, { - fn handle(&self, req: Request, params: P) -> BoxFuture, HyperError> { + fn handle( + &self, + req: Request, + params: P, + ) -> Box, Error = hyper::Error> + Send> { (*self)(req, params) } } @@ -48,14 +57,14 @@ pub trait Builder: Sized { fn route(self, method: Method, pattern: S, handler: H) -> Self where S: AsRef, - H: Handler<::Parameters>; + H: Handler<::Parameters> + Sync; fn finish(self) -> Self::Recognizer; fn get(self, pattern: S, handler: H) -> Self where S: AsRef, - H: Handler<::Parameters>, + H: Handler<::Parameters> + Sync, { self.route(Method::GET, pattern, handler) } @@ -63,7 +72,7 @@ pub trait Builder: Sized { fn post(self, pattern: S, handler: H) -> Self where S: AsRef, - H: Handler<::Parameters>, + H: Handler<::Parameters> + Sync, { self.route(Method::POST, pattern, handler) } @@ -71,7 +80,7 @@ pub trait Builder: Sized { fn put(self, pattern: S, handler: H) -> Self where S: AsRef, - H: Handler<::Parameters>, + H: Handler<::Parameters> + Sync, { self.route(Method::PUT, pattern, handler) } @@ -79,7 +88,7 @@ pub trait Builder: Sized { fn delete(self, pattern: S, handler: H) -> Self where S: AsRef, - H: Handler<::Parameters>, + H: Handler<::Parameters> + Sync, { self.route(Method::DELETE, pattern, handler) } @@ -101,13 +110,15 @@ impl NewService for Router where R: Recognizer, { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Instance = RouterService; - - fn new_service(&self) -> io::Result { - Ok(RouterService { + type ReqBody = ::ReqBody; + type ResBody = ::ResBody; + type Error = ::Error; + type Service = RouterService; + type Future = future::FutureResult; + type InitError = Box; + + fn new_service(&self) -> Self::Future { + future::ok(RouterService { inner: self.inner.clone(), }) } @@ -132,23 +143,23 @@ impl Service for RouterService where R: Recognizer, { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Future = BoxFuture; + type ReqBody = Body; + type ResBody = Body; + type Error = hyper::Error; + type Future = Box, Error = Self::Error> + Send>; - fn call(&self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let method = req.method().clone(); let path = req.uri().path().to_owned(); self.inner .recognize(&method, &path) .map(|(handler, params)| handler.handle(req, params)) .unwrap_or_else(|code| { - Box::new(future::result( + Box::new(future::ok( Response::builder() .status(code) - .body(Body::default()) - .map_err(|_| HyperError::Status), + .body(Body::empty()) + .expect("hyper::Response with empty body should not fail to build"), )) }) } diff --git a/edgelet/edgelet-http/src/route/regex.rs b/edgelet/edgelet-http/src/route/regex.rs index 2cc29869b32..d9ff0af8268 100644 --- a/edgelet/edgelet-http/src/route/regex.rs +++ b/edgelet/edgelet-http/src/route/regex.rs @@ -67,7 +67,7 @@ impl Default for Parameters { struct RegexRoute { pattern: Regex, - handler: Box>, + handler: Box + Sync>, } #[derive(Default)] @@ -81,7 +81,7 @@ impl Builder for RegexRoutesBuilder { fn route(mut self, method: Method, pattern: S, handler: H) -> Self where S: AsRef, - H: Handler<::Parameters>, + H: Handler<::Parameters> + Sync, { let pattern = normalize_pattern(pattern.as_ref()); let pattern = Regex::new(&pattern).expect("failed to compile regex"); diff --git a/edgelet/edgelet-http/src/unix.rs b/edgelet/edgelet-http/src/unix.rs index 7b25c2822c3..c3dff82238f 100644 --- a/edgelet/edgelet-http/src/unix.rs +++ b/edgelet/edgelet-http/src/unix.rs @@ -7,13 +7,12 @@ use std::os::unix::fs::MetadataExt; use std::path::Path; use nix::sys::stat::{umask, Mode}; -use tokio_core::reactor::Handle; use tokio_uds::UnixListener; use error::Error; use util::incoming::Incoming; -pub fn listener>(path: P, handle: &Handle) -> Result { +pub fn listener>(path: P) -> Result { let listener = if path.as_ref().exists() { // get the previous file's metadata let metadata = fs::metadata(&path)?; @@ -40,12 +39,12 @@ pub fn listener>(path: P, handle: &Handle) -> Result Result { + pub fn new(url: &Url) -> Result { match url.scheme() { #[cfg(windows)] - PIPE_SCHEME => Ok(UrlConnector::Pipe(PipeConnector::new(handle.clone()))), + PIPE_SCHEME => Ok(UrlConnector::Pipe(PipeConnector)), #[cfg(unix)] UNIX_SCHEME => { if !Path::new(url.path()).exists() { Err(ErrorKind::InvalidUri(url.to_string()))? } else { - Ok(UrlConnector::Unix(UnixConnector::new(handle.clone()))) + Ok(UrlConnector::Unix(UnixConnector::new())) } } @@ -63,7 +63,7 @@ impl UrlConnector { // NOTE: We are defaulting to using 4 threads here. Is this a good // default? This is what the "hyper" crate uses by default at // this time. - Ok(UrlConnector::Http(HttpConnector::new(4, handle))) + Ok(UrlConnector::Http(HttpConnector::new(4))) } _ => Err(ErrorKind::InvalidUri(url.to_string()))?, } @@ -83,33 +83,49 @@ impl UrlConnector { } } -impl Service for UrlConnector { - type Request = Uri; - type Response = StreamSelector; +impl Connect for UrlConnector { + type Transport = StreamSelector; type Error = io::Error; - type Future = Box>; + type Future = Box + Send>; - fn call(&self, uri: Uri) -> Self::Future { - match *self { - UrlConnector::Http(ref connector) => Box::new( - connector - .call(uri) - .and_then(|tcp_stream| Ok(StreamSelector::Tcp(tcp_stream))), - ) as Self::Future, + fn connect(&self, dst: Destination) -> Self::Future { + match (self, dst.scheme()) { + (UrlConnector::Http(_), HTTP_SCHEME) => (), #[cfg(windows)] - UrlConnector::Pipe(ref connector) => Box::new( - connector - .call(uri) - .and_then(|pipe_stream| Ok(StreamSelector::Pipe(pipe_stream))), - ) as Self::Future, + (UrlConnector::Pipe(_), PIPE_SCHEME) => (), #[cfg(unix)] - UrlConnector::Unix(ref connector) => Box::new( - connector - .call(uri) - .and_then(|unix_stream| Ok(StreamSelector::Unix(unix_stream))), - ) as Self::Future, + (UrlConnector::Unix(_), UNIX_SCHEME) => (), + + (_, scheme) => { + return Box::new(future::err(io::Error::new( + io::ErrorKind::Other, + format!("Invalid scheme {}", scheme), + ))) as Self::Future + } + }; + + match self { + UrlConnector::Http(connector) => { + Box::new(connector.connect(dst).and_then(|(tcp_stream, connected)| { + Ok((StreamSelector::Tcp(tcp_stream), connected)) + })) as Self::Future + } + + #[cfg(windows)] + UrlConnector::Pipe(connector) => { + Box::new(connector.connect(dst).and_then(|(pipe_stream, connected)| { + Ok((StreamSelector::Pipe(pipe_stream), connected)) + })) as Self::Future + } + + #[cfg(unix)] + UrlConnector::Unix(connector) => { + Box::new(connector.connect(dst).and_then(|(unix_stream, connected)| { + Ok((StreamSelector::Unix(unix_stream), connected)) + })) as Self::Future + } } } } @@ -118,7 +134,6 @@ impl Service for UrlConnector { mod tests { #[cfg(unix)] use tempfile::NamedTempFile; - use tokio_core::reactor::Core; use url::Url; use super::*; @@ -126,50 +141,35 @@ mod tests { #[test] #[should_panic(expected = "Invalid uri")] fn invalid_url_scheme() { - let core = Core::new().unwrap(); - let _connector = UrlConnector::new( - &Url::parse("foo:///this/is/not/valid").unwrap(), - &core.handle(), - ).unwrap(); + let _connector = + UrlConnector::new(&Url::parse("foo:///this/is/not/valid").unwrap()).unwrap(); } #[cfg(unix)] #[test] #[should_panic(expected = "Invalid uri")] fn invalid_uds_url() { - let core = Core::new().unwrap(); - let _connector = UrlConnector::new( - &Url::parse("unix:///this/file/does/not/exist").unwrap(), - &core.handle(), - ).unwrap(); + let _connector = + UrlConnector::new(&Url::parse("unix:///this/file/does/not/exist").unwrap()).unwrap(); } #[cfg(unix)] #[test] fn create_uds_succeeds() { - let core = Core::new().unwrap(); let file = NamedTempFile::new().unwrap(); let file_path = file.path().to_str().unwrap(); - let _connector = UrlConnector::new( - &Url::parse(&format!("unix://{}", file_path)).unwrap(), - &core.handle(), - ).unwrap(); + let _connector = + UrlConnector::new(&Url::parse(&format!("unix://{}", file_path)).unwrap()).unwrap(); } #[test] fn create_http_succeeds() { - let core = Core::new().unwrap(); - let _connector = UrlConnector::new( - &Url::parse("http://localhost:2375").unwrap(), - &core.handle(), - ).unwrap(); + let _connector = UrlConnector::new(&Url::parse("http://localhost:2375").unwrap()).unwrap(); } #[cfg(windows)] #[test] fn create_pipe_succeeds() { - let core = Core::new().unwrap(); - let _connector = - UrlConnector::new(&Url::parse("npipe://./pipe/boo").unwrap(), &core.handle()).unwrap(); + let _connector = UrlConnector::new(&Url::parse("npipe://./pipe/boo").unwrap()).unwrap(); } } diff --git a/edgelet/edgelet-http/src/util/hyperwrap.rs b/edgelet/edgelet-http/src/util/hyperwrap.rs index 57849788cb1..0c649f20d0c 100644 --- a/edgelet/edgelet-http/src/util/hyperwrap.rs +++ b/edgelet/edgelet-http/src/util/hyperwrap.rs @@ -2,27 +2,22 @@ use error::Error; use futures::future; -use hyper::client::{HttpConnector, Service}; -use hyper::{Client as HyperClient, Error as HyperError, Request, Response, StatusCode, Uri}; +use hyper::client::HttpConnector; +use hyper::{Body, Client as HyperClient, Error as HyperError, Request, Response, StatusCode, Uri}; use hyper_proxy::{Intercept, Proxy, ProxyConnector}; use hyper_tls::HttpsConnector; -use tokio_core::reactor::Handle; + +use super::super::client::ClientImpl; const DNS_WORKER_THREADS: usize = 4; #[derive(Clone, Debug)] pub struct Config { - handle: Option, proxy_uri: Option, null: bool, } impl Config { - pub fn handle(&mut self, handle: &Handle) -> &mut Config { - self.handle = Some(handle.clone()); - self - } - pub fn proxy(&mut self, uri: Uri) -> &mut Config { self.proxy_uri = Some(uri); self @@ -38,20 +33,13 @@ impl Config { Ok(Client::Null) } else { let config = self.clone(); - let h = &config - .handle - .expect("tokio_core::reactor::Handle expected!"); - let https = HttpsConnector::new(DNS_WORKER_THREADS, &h)?; + let https = HttpsConnector::new(DNS_WORKER_THREADS)?; match config.proxy_uri { - None => Ok(Client::NoProxy( - HyperClient::configure().connector(https).build(h), - )), + None => Ok(Client::NoProxy(HyperClient::builder().build(https))), Some(uri) => { let proxy = Proxy::new(Intercept::All, uri); let conn = ProxyConnector::from_proxy(https, proxy)?; - Ok(Client::Proxy( - HyperClient::configure().connector(conn).build(h), - )) + Ok(Client::Proxy(HyperClient::builder().build(conn))) } } } @@ -68,7 +56,6 @@ pub enum Client { impl Client { pub fn configure() -> Config { Config { - handle: None, proxy_uri: None, null: false, } @@ -91,18 +78,19 @@ impl Client { } } -impl Service for Client { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Future = Box>; +impl ClientImpl for Client { + type Response = Box, Error = HyperError> + Send>; - fn call(&self, req: Self::Request) -> Self::Future { + fn call(&self, req: Request) -> Self::Response { match *self { - Client::NoProxy(ref client) => Box::new(client.call(req)) as Self::Future, - Client::Proxy(ref client) => Box::new(client.call(req)) as Self::Future, + Client::NoProxy(ref client) => Box::new(client.request(req)) as Self::Response, + Client::Proxy(ref client) => Box::new(client.request(req)) as Self::Response, Client::Null => Box::new(future::ok( - Response::new().with_status(StatusCode::Unregistered(234)), + Response::builder() + .status( + StatusCode::from_u16(234).expect("StatusCode::from_u16 should not fail"), + ).body(Body::empty()) + .expect("creating empty resposne should not fail"), )), } } @@ -112,7 +100,6 @@ impl Service for Client { mod tests { use super::Client; use hyper::Uri; - use tokio_core::reactor::Core; // test that the client builder (Config) is wired up correctly to create the // right enum variants @@ -123,13 +110,6 @@ mod tests { assert!(client.is_null()); } - #[test] - fn can_create_null_client_with_handle() { - let h = Core::new().unwrap().handle(); - let client = Client::configure().null().handle(&h).build().unwrap(); - assert!(client.is_null()); - } - #[test] fn can_create_null_client_with_proxy() { let uri = "irrelevant".parse::().unwrap(); @@ -137,37 +117,16 @@ mod tests { assert!(client.is_null()); } - #[test] - fn can_create_null_client_with_everything() { - let h = Core::new().unwrap().handle(); - let uri = "irrelevant".parse::().unwrap(); - let client = Client::configure() - .null() - .handle(&h) - .proxy(uri) - .build() - .unwrap(); - assert!(client.is_null()); - } - - #[test] - #[should_panic(expected = "tokio_core::reactor::Handle expected!")] - fn cannot_create_client_without_handle() { - Client::configure().build().unwrap(); - } - #[test] fn can_create_client() { - let h = Core::new().unwrap().handle(); - let client = Client::configure().handle(&h).build().unwrap(); + let client = Client::configure().build().unwrap(); assert!(!client.has_proxy() && !client.is_null()); } #[test] fn can_create_client_with_proxy() { - let h = Core::new().unwrap().handle(); let uri = "irrelevant".parse::().unwrap(); - let client = Client::configure().handle(&h).proxy(uri).build().unwrap(); + let client = Client::configure().proxy(uri).build().unwrap(); assert!(client.has_proxy()); } diff --git a/edgelet/edgelet-http/src/util/incoming.rs b/edgelet/edgelet-http/src/util/incoming.rs index 4520ef0cf07..1640c936492 100644 --- a/edgelet/edgelet-http/src/util/incoming.rs +++ b/edgelet/edgelet-http/src/util/incoming.rs @@ -2,8 +2,8 @@ use std::io; -use futures::{Async, Poll, Stream}; -use tokio_core::net::TcpListener; +use futures::{Poll, Stream}; +use tokio::net::TcpListener; #[cfg(unix)] use tokio_uds::UnixListener; @@ -20,22 +20,32 @@ impl Stream for Incoming { type Error = io::Error; fn poll(&mut self) -> Poll, Self::Error> { - match *self { + Ok(match *self { Incoming::Tcp(ref mut listener) => { - let (stream, addr) = try_nb!(listener.accept()); - Ok(Async::Ready(Some(( - StreamSelector::Tcp(stream), - IncomingSocketAddr::Tcp(addr), - )))) + let accept = match listener.poll_accept() { + Ok(accept) => accept, + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + return Ok(::futures::Async::NotReady) + } + Err(e) => return Err(e), + }; + accept.map(|(stream, addr)| { + Some((StreamSelector::Tcp(stream), IncomingSocketAddr::Tcp(addr))) + }) } #[cfg(unix)] Incoming::Unix(ref mut listener) => { - let (stream, addr) = try_nb!(listener.accept()); - Ok(Async::Ready(Some(( - StreamSelector::Unix(stream), - IncomingSocketAddr::Unix(addr), - )))) + let accept = match listener.poll_accept() { + Ok(accept) => accept, + Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + return Ok(::futures::Async::NotReady) + } + Err(e) => return Err(e), + }; + accept.map(|(stream, addr)| { + Some((StreamSelector::Unix(stream), IncomingSocketAddr::Unix(addr))) + }) } - } + }) } } diff --git a/edgelet/edgelet-http/src/util/mod.rs b/edgelet/edgelet-http/src/util/mod.rs index adbd460dc9e..79c7a37fcfa 100644 --- a/edgelet/edgelet-http/src/util/mod.rs +++ b/edgelet/edgelet-http/src/util/mod.rs @@ -9,8 +9,8 @@ use std::os::unix::net::SocketAddr as UnixSocketAddr; use bytes::{Buf, BufMut}; use edgelet_core::pid::Pid; use futures::Poll; -use tokio_core::net::TcpStream; -use tokio_io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::net::TcpStream; #[cfg(windows)] use tokio_named_pipe::PipeStream; #[cfg(unix)] @@ -153,14 +153,11 @@ impl fmt::Display for IncomingSocketAddr { #[cfg(unix)] #[cfg(test)] mod tests { - use tokio_core::reactor::Core; - use super::*; #[test] fn test_pid() { - let core = Core::new().unwrap(); - let (a, b) = UnixStream::pair(&core.handle()).unwrap(); + let (a, b) = UnixStream::pair().unwrap(); assert_eq!(a.pid().unwrap(), b.pid().unwrap()); match a.pid().unwrap() { Pid::None => panic!("no pid 'a'"), diff --git a/edgelet/edgelet-http/src/util/proxy.rs b/edgelet/edgelet-http/src/util/proxy.rs index 206ed0e2952..cf406b66738 100644 --- a/edgelet/edgelet-http/src/util/proxy.rs +++ b/edgelet/edgelet-http/src/util/proxy.rs @@ -1,10 +1,9 @@ // Copyright (c) Microsoft. All rights reserved. +use super::super::client::ClientImpl; use super::hyperwrap::Client; use error::Error; -use hyper::client::Service; -use hyper::Uri; -use tokio_core::reactor::Handle; +use hyper::{Body, Request, Uri}; #[derive(Clone)] pub struct MaybeProxyClient { @@ -12,15 +11,13 @@ pub struct MaybeProxyClient { } impl MaybeProxyClient { - pub fn new(handle: &Handle, proxy_uri: Option) -> Result { - MaybeProxyClient::create(Some(handle), proxy_uri) + pub fn new(proxy_uri: Option) -> Result { + MaybeProxyClient::create(false, proxy_uri) } - fn create(handle: Option<&Handle>, proxy_uri: Option) -> Result { + fn create(null: bool, proxy_uri: Option) -> Result { let mut config = Client::configure(); - if let Some(h) = handle { - config.handle(h); - } else { + if null { config.null(); } if let Some(uri) = proxy_uri { @@ -33,7 +30,7 @@ impl MaybeProxyClient { #[cfg(test)] pub fn new_null() -> Result { - MaybeProxyClient::create(None, None) + MaybeProxyClient::create(true, None) } #[cfg(test)] @@ -47,38 +44,32 @@ impl MaybeProxyClient { } } -impl Service for MaybeProxyClient { - type Request = ::Request; - type Response = ::Response; - type Error = ::Error; - type Future = ::Future; +impl ClientImpl for MaybeProxyClient { + type Response = ::Response; - fn call(&self, req: Self::Request) -> Self::Future { + fn call(&self, req: Request) -> Self::Response { self.client.call(req) } } #[cfg(test)] mod tests { + use super::super::super::client::ClientImpl; use super::MaybeProxyClient; use futures::Future; use http::Request; - use hyper::client::Service; use hyper::{StatusCode, Uri}; - use tokio_core::reactor::Core; #[test] fn can_create_client() { - let handle = Core::new().unwrap().handle(); - let client = MaybeProxyClient::new(&handle, None).unwrap(); + let client = MaybeProxyClient::new(None).unwrap(); assert!(!client.has_proxy() && !client.is_null()); } #[test] fn can_create_client_with_proxy() { - let handle = Core::new().unwrap().handle(); let uri = "irrelevant".parse::().unwrap(); - let client = MaybeProxyClient::new(&handle, Some(uri)).unwrap(); + let client = MaybeProxyClient::new(Some(uri)).unwrap(); assert!(client.has_proxy() && !client.is_null()); } @@ -86,6 +77,9 @@ mod tests { fn client_calls_underlying_service() { let client = MaybeProxyClient::new_null().unwrap(); let response = client.call(Request::default().into()).wait().unwrap(); - assert_eq!(response.status(), StatusCode::Unregistered(234)); + assert_eq!( + response.status(), + StatusCode::from_u16(234).expect("StatusCode::from_u16 should not fail") + ); } } diff --git a/edgelet/edgelet-http/src/version.rs b/edgelet/edgelet-http/src/version.rs index c94f22cefb9..5f8ac3f42ea 100644 --- a/edgelet/edgelet-http/src/version.rs +++ b/edgelet/edgelet-http/src/version.rs @@ -1,11 +1,11 @@ // Copyright (c) Microsoft. All rights reserved. +use std::error::Error as StdError; use std::io; use futures::{future, Future}; -use http::{Request, Response}; -use hyper::server::{NewService, Service}; -use hyper::{Body, Error as HyperError}; +use hyper::service::{NewService, Service}; +use hyper::{Body, Error as HyperError, Request, Response}; use url::form_urlencoded::parse as parse_query; use error::{Error, ErrorKind}; @@ -24,23 +24,18 @@ impl ApiVersionService { } } -impl IntoResponse for HyperError { - fn into_response(self) -> Response { - Error::from(self).into_response() - } -} - impl Service for ApiVersionService where - T: Service, Response = Response, Error = HyperError>, - T::Future: 'static, + T: Service, + T::Future: 'static + Send, + T::Error: 'static + IntoResponse + Send, { - type Request = T::Request; - type Response = T::Response; + type ReqBody = T::ReqBody; + type ResBody = T::ResBody; type Error = T::Error; - type Future = Box>; + type Future = Box, Error = Self::Error> + Send>; - fn call(&self, req: Self::Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { let response = req .uri() .query() @@ -67,16 +62,30 @@ where impl NewService for ApiVersionService where - T: Clone + Service, Response = Response, Error = HyperError>, - T::Future: 'static, + T: Clone + Service, + T::Future: 'static + Send, { - type Request = T::Request; - type Response = Response; - type Error = HyperError; - type Instance = Self; + type ReqBody = ::ReqBody; + type ResBody = ::ResBody; + type Error = ::Error; + type Service = Self; + type Future = future::FutureResult; + type InitError = Box; + + fn new_service(&self) -> Self::Future { + future::ok(self.clone()) + } +} - fn new_service(&self) -> io::Result { - Ok(self.clone()) +impl IntoResponse for HyperError { + fn into_response(self) -> Response { + Error::from(self).into_response() + } +} + +impl IntoResponse for io::Error { + fn into_response(self) -> Response { + Error::from(self).into_response() } } @@ -84,6 +93,7 @@ where mod tests { use super::*; use http::StatusCode; + use std::io; #[derive(Clone)] struct TestService { @@ -92,14 +102,14 @@ mod tests { } impl Service for TestService { - type Request = Request; - type Response = Response; - type Error = HyperError; - type Future = Box>; + type ReqBody = Body; + type ResBody = Body; + type Error = io::Error; + type Future = Box, Error = Self::Error> + Send>; - fn call(&self, _req: Self::Request) -> Self::Future { + fn call(&mut self, _req: Request) -> Self::Future { Box::new(if self.error { - future::err(HyperError::TooLarge) + future::err(io::Error::new(io::ErrorKind::Other, "TestService error")) } else { future::ok( Response::builder() @@ -115,11 +125,11 @@ mod tests { fn api_version_check_succeeds() { let url = &format!("http://localhost?api-version={}", API_VERSION); let req = Request::get(url).body(Body::default()).unwrap(); - let api_service = ApiVersionService::new(TestService { + let mut api_service = ApiVersionService::new(TestService { status_code: StatusCode::OK, error: false, }); - let response = Service::call(&api_service, req).wait().unwrap(); + let response = Service::call(&mut api_service, req).wait().unwrap(); assert_eq!(StatusCode::OK, response.status()); } @@ -127,11 +137,11 @@ mod tests { fn api_version_check_passes_status_code_through() { let url = &format!("http://localhost?api-version={}", API_VERSION); let req = Request::get(url).body(Body::default()).unwrap(); - let api_service = ApiVersionService::new(TestService { + let mut api_service = ApiVersionService::new(TestService { status_code: StatusCode::IM_A_TEAPOT, error: false, }); - let response = Service::call(&api_service, req).wait().unwrap(); + let response = Service::call(&mut api_service, req).wait().unwrap(); assert_eq!(StatusCode::IM_A_TEAPOT, response.status()); } @@ -139,11 +149,11 @@ mod tests { fn api_version_check_returns_error_as_response() { let url = &format!("http://localhost?api-version={}", API_VERSION); let req = Request::get(url).body(Body::default()).unwrap(); - let api_service = ApiVersionService::new(TestService { + let mut api_service = ApiVersionService::new(TestService { status_code: StatusCode::IM_A_TEAPOT, error: true, }); - let response = Service::call(&api_service, req).wait().unwrap(); + let response = Service::call(&mut api_service, req).wait().unwrap(); assert_eq!(StatusCode::INTERNAL_SERVER_ERROR, response.status()); } @@ -151,11 +161,11 @@ mod tests { fn api_version_does_not_exist() { let url = "http://localhost"; let req = Request::get(url).body(Body::default()).unwrap(); - let api_service = ApiVersionService::new(TestService { + let mut api_service = ApiVersionService::new(TestService { status_code: StatusCode::OK, error: false, }); - let response = Service::call(&api_service, req).wait().unwrap(); + let response = Service::call(&mut api_service, req).wait().unwrap(); assert_eq!(StatusCode::BAD_REQUEST, response.status()); } @@ -163,11 +173,11 @@ mod tests { fn api_version_is_unsupported() { let url = "http://localhost?api-version=not-a-valid-version"; let req = Request::get(url).body(Body::default()).unwrap(); - let api_service = ApiVersionService::new(TestService { + let mut api_service = ApiVersionService::new(TestService { status_code: StatusCode::OK, error: false, }); - let response = Service::call(&api_service, req).wait().unwrap(); + let response = Service::call(&mut api_service, req).wait().unwrap(); assert_eq!(StatusCode::BAD_REQUEST, response.status()); } } diff --git a/edgelet/edgelet-http/tests/connector.rs b/edgelet/edgelet-http/tests/connector.rs index d2baed45c0c..1145edd65fc 100644 --- a/edgelet/edgelet-http/tests/connector.rs +++ b/edgelet/edgelet-http/tests/connector.rs @@ -17,10 +17,15 @@ extern crate rand; #[cfg(unix)] #[macro_use(defer)] extern crate scopeguard; -extern crate tokio_core; +extern crate tokio; +extern crate typed_headers; extern crate url; +#[cfg(unix)] +use std::io; +#[cfg(windows)] use std::sync::mpsc::channel; +#[cfg(windows)] use std::thread; use edgelet_http::UrlConnector; @@ -33,64 +38,56 @@ use futures::future; use futures::prelude::*; #[cfg(windows)] use httparse::Request as HtRequest; -use hyper::header::{ContentLength, ContentType}; -use hyper::server::{Request, Response}; -use hyper::Error as HyperError; -use hyper::{Client, Method, Request as ClientRequest, StatusCode}; +use hyper::{ + Body, Client, Error as HyperError, Method, Request, Response, StatusCode, Uri as HyperUri, +}; #[cfg(windows)] use hyper_named_pipe::Uri as PipeUri; #[cfg(unix)] use hyperlocal::Uri as HyperlocalUri; #[cfg(windows)] use rand::Rng; -use tokio_core::reactor::Core; +use typed_headers::mime; +use typed_headers::{ContentLength, ContentType, HeaderMapExt}; use url::Url; const GET_RESPONSE: &str = "Yo"; -fn hello_handler(_: Request) -> Box> { - Box::new(future::ok( - Response::new() - .with_header(ContentLength(GET_RESPONSE.len() as u64)) - .with_body(GET_RESPONSE), - )) +fn hello_handler(_: Request) -> impl Future, Error = HyperError> { + let mut response = Response::new(GET_RESPONSE.into()); + response + .headers_mut() + .typed_insert(&ContentLength(GET_RESPONSE.len() as u64)); + future::ok(response) } #[test] fn tcp_get() { - let (sender, receiver) = channel(); - let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server("127.0.0.1", port, hello_handler, &sender); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + let server = + run_tcp_server("127.0.0.1", port, hello_handler).map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); let url = format!("http://localhost:{}", port); - let connector = UrlConnector::new(&Url::parse(&url).unwrap(), &core.handle()).unwrap(); + let connector = UrlConnector::new(&Url::parse(&url).unwrap()).unwrap(); - let client = Client::configure() - .connector(connector) - .build(&core.handle()); + let client = Client::builder().build::<_, Body>(connector); let task = client .get(url.parse().unwrap()) .and_then(|res| { - assert_eq!(StatusCode::Ok, res.status()); - res.body().concat2() + assert_eq!(StatusCode::OK, res.status()); + res.into_body().concat2() }).map(|body| { assert_eq!(GET_RESPONSE, &String::from_utf8_lossy(body.as_ref())); }); - core.run(task).unwrap(); + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } #[cfg(unix)] #[test] fn uds_get() { - let (sender, receiver) = channel(); let file_path = "/tmp/edgelet_test_uds_get.sock"; // make sure file gets deleted when test is done @@ -99,32 +96,26 @@ fn uds_get() { }} let path_copy = file_path.to_string(); - thread::spawn(move || { - run_uds_server(&path_copy, hello_handler, &sender); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + let server = run_uds_server(&path_copy, |req| { + hello_handler(req).map_err(|err| io::Error::new(io::ErrorKind::Other, err)) + }).map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); - let connector = UrlConnector::new( - &Url::parse(&format!("unix://{}", file_path)).unwrap(), - &core.handle(), - ).unwrap(); + let connector = + UrlConnector::new(&Url::parse(&format!("unix://{}", file_path)).unwrap()).unwrap(); - let client = Client::configure() - .connector(connector) - .build(&core.handle()); + let client = Client::builder().build::<_, Body>(connector); let task = client .get(HyperlocalUri::new(&file_path, "/").into()) .and_then(|res| { - assert_eq!(StatusCode::Ok, res.status()); - res.body().concat2() + assert_eq!(StatusCode::OK, res.status()); + res.into_body().concat2() }).map(|body| { assert_eq!(GET_RESPONSE, &String::from_utf8_lossy(body.as_ref())); }); - core.run(task).unwrap(); + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } #[cfg(windows)] @@ -164,77 +155,75 @@ fn pipe_get() { // wait for server to get ready receiver.recv().unwrap(); - let mut core = Core::new().unwrap(); - let connector = UrlConnector::new(&Url::parse(&url).unwrap(), &core.handle()).unwrap(); + let connector = UrlConnector::new(&Url::parse(&url).unwrap()).unwrap(); - let hyper_client = Client::configure() - .connector(connector) - .build(&core.handle()); + let client = Client::builder().build::<_, Body>(connector); // make a get request - let task = hyper_client + let task = client .get(PipeUri::new(&url, "/").unwrap().into()) .and_then(|res| { - assert_eq!(StatusCode::Ok, res.status()); - res.body().concat2() + assert_eq!(StatusCode::OK, res.status()); + res.into_body().concat2() }).map(|body| { assert_eq!(GET_RESPONSE, &String::from_utf8_lossy(body.as_ref())); }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } const POST_BODY: &str = r#"{"donuts":"yes"}"#; -fn post_handler(req: Request) -> Box> { +fn post_handler( + req: Request, +) -> Box, Error = HyperError> + Send> { // verify that the request body is what we expect Box::new( - req.body() + req.into_body() .concat2() .and_then(|body| { assert_eq!(POST_BODY, &String::from_utf8_lossy(body.as_ref())); Ok(()) - }).map(|_| Response::new().with_status(StatusCode::Ok)), + }).map(|_| Response::new(Body::empty())), ) } #[test] fn tcp_post() { - let (sender, receiver) = channel(); - let port = get_unused_tcp_port(); - thread::spawn(move || { - run_tcp_server("127.0.0.1", port, post_handler, &sender); - }); - - // wait for server to get ready - receiver.recv().unwrap(); + let server = + run_tcp_server("127.0.0.1", port, post_handler).map_err(|err| eprintln!("{}", err)); - let mut core = Core::new().unwrap(); let url = format!("http://localhost:{}", port); - let connector = UrlConnector::new(&Url::parse(&url).unwrap(), &core.handle()).unwrap(); + let connector = UrlConnector::new(&Url::parse(&url).unwrap()).unwrap(); - let client = Client::configure() - .connector(connector) - .build(&core.handle()); + let client = Client::builder().build::<_, Body>(connector); - let url = url.parse().unwrap(); - let mut req = ClientRequest::new(Method::Post, url); - req.headers_mut().set(ContentType::json()); - req.headers_mut().set(ContentLength(POST_BODY.len() as u64)); - req.set_body(POST_BODY); + let mut req = Request::builder() + .method(Method::POST) + .uri(url) + .body(POST_BODY.into()) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&ContentLength(POST_BODY.len() as u64)); let task = client.request(req).map(|res| { - assert_eq!(StatusCode::Ok, res.status()); + assert_eq!(StatusCode::OK, res.status()); }); - core.run(task).unwrap(); + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } #[cfg(unix)] #[test] fn uds_post() { - let (sender, receiver) = channel(); let file_path = "/tmp/edgelet_test_uds_post.sock"; // make sure file gets deleted when test is done @@ -243,34 +232,34 @@ fn uds_post() { }} let path_copy = file_path.to_string(); - thread::spawn(move || { - run_uds_server(&path_copy, hello_handler, &sender); - }); + let server = run_uds_server(&path_copy, |req| { + hello_handler(req).map_err(|err| io::Error::new(io::ErrorKind::Other, err)) + }).map_err(|err| eprintln!("{}", err)); - // wait for server to get ready - receiver.recv().unwrap(); + let connector = + UrlConnector::new(&Url::parse(&format!("unix://{}", file_path)).unwrap()).unwrap(); - let mut core = Core::new().unwrap(); - let connector = UrlConnector::new( - &Url::parse(&format!("unix://{}", file_path)).unwrap(), - &core.handle(), - ).unwrap(); + let client = Client::builder().build::<_, Body>(connector); - let client = Client::configure() - .connector(connector) - .build(&core.handle()); + let url: HyperUri = HyperlocalUri::new(&file_path, "/").into(); - let url = HyperlocalUri::new(&file_path, "/").into(); - let mut req = ClientRequest::new(Method::Post, url); - req.headers_mut().set(ContentType::json()); - req.headers_mut().set(ContentLength(POST_BODY.len() as u64)); - req.set_body(POST_BODY); + let mut req = Request::builder() + .method(Method::POST) + .uri(url) + .body(POST_BODY.into()) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&ContentLength(POST_BODY.len() as u64)); let task = client.request(req).map(|res| { - assert_eq!(StatusCode::Ok, res.status()); + assert_eq!(StatusCode::OK, res.status()); }); - core.run(task).unwrap(); + let mut runtime = tokio::runtime::current_thread::Runtime::new().unwrap(); + runtime.spawn(server); + runtime.block_on(task).unwrap(); } #[cfg(windows)] @@ -297,22 +286,29 @@ fn pipe_post() { // wait for server to get ready receiver.recv().unwrap(); - let mut core = Core::new().unwrap(); - let connector = UrlConnector::new(&Url::parse(&url).unwrap(), &core.handle()).unwrap(); + let connector = UrlConnector::new(&Url::parse(&url).unwrap()).unwrap(); + + let client = Client::builder().build::<_, Body>(connector); - let hyper_client = Client::configure() - .connector(connector) - .build(&core.handle()); + let url: HyperUri = PipeUri::new(&url, "/").unwrap().into(); // make a post request - let mut req = Request::new(Method::Post, PipeUri::new(&url, "/").unwrap().into()); - req.headers_mut().set(ContentType::json()); - req.headers_mut().set(ContentLength(POST_BODY.len() as u64)); - req.set_body(POST_BODY); + let mut req = Request::builder() + .method(Method::POST) + .uri(url) + .body(POST_BODY.into()) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&ContentLength(POST_BODY.len() as u64)); - let task = hyper_client.request(req).map(|res| { - assert_eq!(StatusCode::Ok, res.status()); + let task = client.request(req).map(|res| { + assert_eq!(StatusCode::OK, res.status()); }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } diff --git a/edgelet/edgelet-http/tests/route.rs b/edgelet/edgelet-http/tests/route.rs index fb86cec6ca4..f6f57097084 100644 --- a/edgelet/edgelet-http/tests/route.rs +++ b/edgelet/edgelet-http/tests/route.rs @@ -6,13 +6,16 @@ extern crate http; extern crate hyper; extern crate regex; -use edgelet_http::route::{BoxFuture, Builder, Parameters, RegexRoutesBuilder, Router}; +use edgelet_http::route::{Builder, Parameters, RegexRoutesBuilder, Router}; use futures::{future, Future, Stream}; use http::{Request, Response, StatusCode}; -use hyper::server::{NewService, Service}; +use hyper::service::{NewService, Service}; use hyper::{Body, Chunk, Error as HyperError}; -fn route1(_req: Request, params: Parameters) -> BoxFuture, HyperError> { +fn route1( + _req: Request, + params: Parameters, +) -> Box, Error = HyperError> + Send> { let response = params .name("name") .map(|name| { @@ -29,7 +32,10 @@ fn route1(_req: Request, params: Parameters) -> BoxFuture, Box::new(future::ok(response)) } -fn route2(_req: Request, params: Parameters) -> BoxFuture, HyperError> { +fn route2( + _req: Request, + params: Parameters, +) -> Box, Error = HyperError> + Send> { let response = params .name("name") .map(|name| { @@ -53,7 +59,7 @@ fn simple_route() { .get("/route2/(?P[^/]+)", route2) .finish(); let router = Router::from(recognizer); - let service = router.new_service().unwrap(); + let mut service = router.new_service().wait().unwrap(); let uri1 = "http://example.com/route1/thename"; let request1 = Request::get(uri1).body(Body::default()).unwrap(); @@ -88,7 +94,7 @@ fn not_found() { .get("/route2/(?P[^/]+)", route2) .finish(); let router = Router::from(recognizer); - let service = router.new_service().unwrap(); + let mut service = router.new_service().wait().unwrap(); let uri1 = "http://example.com/route3/thename"; let request1 = Request::get(uri1).body(Body::default()).unwrap(); diff --git a/edgelet/edgelet-http/tests/systemd.rs b/edgelet/edgelet-http/tests/systemd.rs new file mode 100644 index 00000000000..6f74e0e807c --- /dev/null +++ b/edgelet/edgelet-http/tests/systemd.rs @@ -0,0 +1,125 @@ +#![cfg(target_os = "linux")] + +// These tests are sensitive to the number of FDs open in the current process. +// Specifically, the tests require that fd 3 be available to be bound to a socket +// to simulate what happens when systemd passes down sockets during socket activation. +// +// Thus these tests are in their own separate test crate, and use a Mutex to ensure +// that only one runs at a time. + +extern crate edgelet_http; +extern crate futures; +extern crate hyper; +#[macro_use] +extern crate lazy_static; +extern crate nix; +extern crate systemd; +extern crate url; + +use std::sync::{Mutex, MutexGuard}; +use std::{env, io}; + +use edgelet_http::HyperExt; +use futures::{future, Future}; +use hyper::server::conn::Http; +use hyper::service::Service; +use hyper::{Body, Request, Response, StatusCode}; +use nix::sys::socket::{self, AddressFamily, SockType}; +use nix::unistd::{self, getpid}; +use systemd::Fd; +use url::Url; + +lazy_static! { + static ref LOCK: Mutex<()> = Mutex::new(()); +} + +const ENV_FDS: &str = "LISTEN_FDS"; +const ENV_PID: &str = "LISTEN_PID"; + +#[derive(Clone)] +struct TestService { + status_code: StatusCode, + error: bool, +} + +impl Service for TestService { + type ReqBody = Body; + type ResBody = Body; + type Error = io::Error; + type Future = Box, Error = Self::Error>>; + + fn call(&mut self, _req: Request) -> Self::Future { + Box::new(if self.error { + future::err(io::Error::new(io::ErrorKind::Other, "TestService error")) + } else { + future::ok( + Response::builder() + .status(self.status_code) + .body(Body::default()) + .unwrap(), + ) + }) + } +} + +fn lock_env<'a>() -> MutexGuard<'a, ()> { + LOCK.lock().unwrap() +} + +fn set_current_pid() { + let pid = getpid(); + env::set_var(ENV_PID, format!("{}", pid)); +} + +fn create_fd(family: AddressFamily, type_: SockType) -> Fd { + let fd = socket::socket(family, type_, socket::SockFlag::empty(), None).unwrap(); + fd +} + +#[test] +fn test_fd_ok() { + let _l = lock_env(); + set_current_pid(); + let fd = create_fd(AddressFamily::Unix, SockType::Stream); + assert_eq!(fd, 3); + + // set the env var so that it contains the created fd + env::set_var(ENV_FDS, format!("{}", fd - 3 + 1)); + + let url = Url::parse(&format!("fd://{}", fd - 3)).unwrap(); + let run = Http::new().bind_url(url, move || { + let service = TestService { + status_code: StatusCode::OK, + error: false, + }; + Ok::<_, io::Error>(service) + }); + + unistd::close(fd).unwrap(); + if let Err(err) = run { + panic!("{:?}", err); + } +} + +#[test] +fn test_fd_err() { + let _l = lock_env(); + set_current_pid(); + let fd = create_fd(AddressFamily::Unix, SockType::Stream); + assert_eq!(fd, 3); + + // set the env var so that it contains the created fd + env::set_var(ENV_FDS, format!("{}", fd - 3 + 1)); + + let url = Url::parse("fd://100").unwrap(); + let run = Http::new().bind_url(url, move || { + let service = TestService { + status_code: StatusCode::OK, + error: false, + }; + Ok::<_, io::Error>(service) + }); + + unistd::close(fd).unwrap(); + assert!(run.is_err()); +} diff --git a/edgelet/edgelet-iothub/Cargo.toml b/edgelet/edgelet-iothub/Cargo.toml index b5bd73c025c..7dc0e67799a 100644 --- a/edgelet/edgelet-iothub/Cargo.toml +++ b/edgelet/edgelet-iothub/Cargo.toml @@ -9,7 +9,6 @@ base64 = "0.9" chrono = "0.4" failure = "0.1" futures = "0.1" -hyper = "0.11" percent-encoding = "1.0" serde = "1.0" serde_derive = "1.0" @@ -22,5 +21,7 @@ iothubservice = { path = "../iothubservice" } [dev_dependencies] bytes = "0.4" +hyper = "0.12" serde_json = "1.0" -tokio-core = "0.1" +tokio = "0.1.8" +typed-headers = "0.1" diff --git a/edgelet/edgelet-iothub/src/lib.rs b/edgelet/edgelet-iothub/src/lib.rs index b8dd7b67c70..4b4aac7c91e 100644 --- a/edgelet/edgelet-iothub/src/lib.rs +++ b/edgelet/edgelet-iothub/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] extern crate base64; #[cfg(test)] @@ -9,16 +9,18 @@ extern crate chrono; #[macro_use] extern crate failure; extern crate futures; +#[cfg(test)] extern crate hyper; #[macro_use] extern crate percent_encoding; -extern crate serde; #[macro_use] extern crate serde_derive; #[cfg(test)] extern crate serde_json; #[cfg(test)] -extern crate tokio_core; +extern crate tokio; +#[cfg(test)] +extern crate typed_headers; extern crate url; extern crate edgelet_core; @@ -30,20 +32,18 @@ mod error; use std::convert::AsRef; use std::marker::PhantomData; -use std::rc::Rc; +use std::sync::Arc; use chrono::{DateTime, Utc}; use failure::ResultExt; use futures::future::{self, Either}; use futures::Future; -use hyper::client::Service; -use hyper::{Error as HyperError, Request, Response}; use percent_encoding::{percent_encode, PATH_SEGMENT_ENCODE_SET}; use url::form_urlencoded::Serializer as UrlSerializer; use edgelet_core::crypto::{KeyIdentity, KeyStore, Sign, Signature, SignatureAlgorithm}; use edgelet_core::{AuthType, Identity, IdentityManager, IdentitySpec}; -use edgelet_http::client::TokenSource; +use edgelet_http::client::{ClientImpl, TokenSource}; use iothubservice::{ AuthMechanism, AuthType as HubAuthType, DeviceClient, ErrorKind as HubErrorKind, Module, SymmetricKey, @@ -112,15 +112,15 @@ fn convert_auth_type(hub_auth_type: &HubAuthType) -> AuthType { } } -struct State +struct State where K: KeyStore, K::Key: AsRef<[u8]> + Clone, - S: 'static + Service, + C: ClientImpl, D: 'static + Sign + Clone, { key_store: K, - client: DeviceClient>, + client: DeviceClient>, } pub struct SasTokenSource @@ -187,30 +187,27 @@ where } } -pub struct HubIdentityManager +pub struct HubIdentityManager where K: KeyStore, K::Key: AsRef<[u8]> + Clone, - S: 'static + Service, + C: ClientImpl, D: 'static + Sign + Clone, { - state: Rc>, + state: Arc>, phantom: PhantomData, } -impl HubIdentityManager +impl HubIdentityManager where K: KeyStore, K::Key: AsRef<[u8]> + Clone, - S: 'static + Service, + C: ClientImpl, D: 'static + Sign + Clone, { - pub fn new( - key_store: K, - client: DeviceClient>, - ) -> HubIdentityManager { + pub fn new(key_store: K, client: DeviceClient>) -> Self { HubIdentityManager { - state: Rc::new(State { key_store, client }), + state: Arc::new(State { key_store, client }), phantom: PhantomData, } } @@ -237,11 +234,11 @@ fn build_key_name(key_name: &str, generation_id: &str) -> String { format!("{}{}", key_name, generation_id) } -impl Clone for HubIdentityManager +impl Clone for HubIdentityManager where K: KeyStore, K::Key: AsRef<[u8]> + Clone, - S: 'static + Service, + C: ClientImpl, D: 'static + Sign + Clone, { fn clone(&self) -> Self { @@ -252,20 +249,20 @@ where } } -impl IdentityManager for HubIdentityManager +impl IdentityManager for HubIdentityManager where - K: 'static + KeyStore, - K::Key: AsRef<[u8]> + Clone, - S: 'static + Service, - D: 'static + Sign + Clone, + K: 'static + KeyStore + Send + Sync, + K::Key: AsRef<[u8]> + Clone + Send, + C: 'static + ClientImpl, + D: 'static + Sign + Clone + Send + Sync, { type Identity = HubIdentity; type Error = Error; - type CreateFuture = Box>; - type UpdateFuture = Box>; - type ListFuture = Box, Error = Self::Error>>; - type GetFuture = Box, Error = Self::Error>>; - type DeleteFuture = Box>; + type CreateFuture = Box + Send>; + type UpdateFuture = Box + Send>; + type ListFuture = Box, Error = Self::Error> + Send>; + type GetFuture = Box, Error = Self::Error> + Send>; + type DeleteFuture = Box + Send>; fn create(&mut self, id: IdentitySpec) -> Self::CreateFuture { // This code first creates a module in the hub with the auth type @@ -382,10 +379,8 @@ mod tests { use bytes::Bytes; use chrono::TimeZone; use futures::Stream; - use hyper::header::{ContentType, IfMatch}; - use hyper::server::service_fn; - use hyper::{Method, Request, Response, StatusCode}; - use tokio_core::reactor::Core; + use hyper::{self, Body, Method, Request, Response, StatusCode}; + use typed_headers::{mime, ContentType, HeaderMapExt}; use url::Url; use edgelet_core::crypto::{MemoryKey, MemoryKeyStore}; @@ -415,18 +410,13 @@ mod tests { let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = |_req: Request| Ok(Response::new().with_status(StatusCode::Ok)); + let handler = |_req: Request| Ok(Response::new(Body::empty())); let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let identity_manager = HubIdentityManager::new(key_store, device_client); @@ -442,18 +432,13 @@ mod tests { let key_store = MemoryKeyStore::new(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = |_req: Request| Ok(Response::new().with_status(StatusCode::Ok)); + let handler = |_req: Request| Ok(Response::new(Body::empty())); let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let identity_manager = HubIdentityManager::new(key_store, device_client); @@ -472,18 +457,13 @@ mod tests { let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = |_req: Request| Ok(Response::new().with_status(StatusCode::Ok)); + let handler = |_req: Request| Ok(Response::new(Body::empty())); let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let identity_manager = HubIdentityManager::new(key_store, device_client); @@ -502,18 +482,13 @@ mod tests { let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = |_req: Request| Ok(Response::new().with_status(StatusCode::Ok)); + let handler = |_req: Request| Ok(Response::new(Body::empty())); let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let identity_manager = HubIdentityManager::new(key_store, device_client); @@ -554,15 +529,15 @@ mod tests { .with_generation_id("g1".to_string()) .with_managed_by("iotedge".to_string()); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Put); - assert_eq!(req.path(), "/devices/d1/modules/m1"); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::PUT); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); // if the request has an If-Match header then this is an update // module request let mut is_update = false; - if let Some(header) = req.headers().get::() { - assert_eq!(header, &IfMatch::Any); + if let Some(header) = req.headers().get(hyper::header::IF_MATCH) { + assert_eq!(header, "*"); is_update = true; } @@ -572,23 +547,24 @@ mod tests { expected_module1.clone() }; - req.body() + req.into_body() .concat2() .and_then(|req_body| Ok(serde_json::from_slice::(&req_body).unwrap())) .and_then(move |module| { assert_eq!(module, expected_module_copy); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body( - serde_json::to_string( - &module - .with_generation_id("g1".to_string()) - .with_managed_by("iotedge".to_string()), - ).unwrap() - .into_bytes(), - )) + let mut response = Response::new( + serde_json::to_string( + &module + .with_generation_id("g1".to_string()) + .with_managed_by("iotedge".to_string()), + ).unwrap() + .into(), + ); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }) }; let token_source = SasTokenSource::new( @@ -596,18 +572,16 @@ mod tests { "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let mut identity_manager = HubIdentityManager::new(key_store, device_client); let task = identity_manager.create(IdentitySpec::new("m1")); - let hub_identity = Core::new().unwrap().run(task).unwrap(); + let hub_identity = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); assert_eq!(hub_identity.hub_module(), &expected_module_result); } @@ -683,44 +657,43 @@ mod tests { .with_managed_by("iotedge".to_string()) }).collect::>(); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/devices/d1/modules"); - - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body( - serde_json::to_string( - &response_modules - .iter() - .map(|module| { - module - .clone() - .with_generation_id("g1".to_string()) - .with_managed_by("iotedge".to_string()) - }).collect::>(), - ).unwrap() - .into_bytes(), - )) + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/devices/d1/modules"); + + let mut response = Response::new( + serde_json::to_string( + &response_modules + .iter() + .map(|module| { + module + .clone() + .with_generation_id("g1".to_string()) + .with_managed_by("iotedge".to_string()) + }).collect::>(), + ).unwrap() + .into(), + ); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }; let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let identity_manager = HubIdentityManager::new(key_store, device_client); let task = identity_manager.list(); - let hub_identities = Core::new().unwrap().run(task).unwrap(); + let hub_identities = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); for hub_identity in hub_identities { assert_eq!( @@ -769,40 +742,40 @@ mod tests { .with_generation_id("g1".to_string()) .with_managed_by("iotedge".to_string()); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/devices/d1/modules/m1"); - - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body( - serde_json::to_string( - &response_module - .clone() - .with_generation_id("g1".to_string()) - .with_managed_by("iotedge".to_string()), - ).unwrap() - .into_bytes(), - )) + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); + + let mut response = Response::new( + serde_json::to_string( + &response_module + .clone() + .with_generation_id("g1".to_string()) + .with_managed_by("iotedge".to_string()), + ).unwrap() + .into(), + ); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }; let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let identity_manager = HubIdentityManager::new(key_store, device_client); let task = identity_manager.get(IdentitySpec::new("m1")); - let hub_identity = Core::new().unwrap().run(task).unwrap().unwrap(); + let hub_identity = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap() + .unwrap(); assert_eq!(hub_identity.hub_module(), &expected_module_result); } @@ -813,29 +786,31 @@ mod tests { let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/devices/d1/modules/m1"); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); - Ok(Response::new().with_status(StatusCode::NotFound)) + let response = Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .expect("could not build hyper::Response"); + Ok(response) }; let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let identity_manager = HubIdentityManager::new(key_store, device_client); let task = identity_manager.get(IdentitySpec::new("m1")); - let hub_identity = Core::new().unwrap().run(task).unwrap(); + let hub_identity = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); assert_eq!(None, hub_identity); } @@ -846,23 +821,18 @@ mod tests { let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Delete); - assert_eq!(req.path(), "/devices/d1/modules/m1"); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::DELETE); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); - Ok(Response::new().with_status(StatusCode::Ok)) + Ok(Response::new(Body::empty())) }; let token_source = SasTokenSource::new( "hub".to_string(), "device".to_string(), MemoryKey::new("device"), ); - let client = Client::new( - service_fn(handler), - Some(token_source), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(token_source), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let mut identity_manager = HubIdentityManager::new(key_store, device_client); @@ -870,7 +840,10 @@ mod tests { .delete(IdentitySpec::new("m1")) .then(|result| Ok(assert_eq!(result.unwrap(), ())) as Result<(), Error>); - Core::new().unwrap().run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] diff --git a/edgelet/edgelet-test-utils/Cargo.toml b/edgelet/edgelet-test-utils/Cargo.toml index 7c922dfe658..56d41fed775 100644 --- a/edgelet/edgelet-test-utils/Cargo.toml +++ b/edgelet/edgelet-test-utils/Cargo.toml @@ -7,18 +7,18 @@ publish = false [dependencies] failure = "0.1" futures = "0.1" -hyper = "0.11" +hyper = "0.12" serde = "1" serde_derive = "1" serde_json = "1" -tokio-io = "0.1" +tokio = "0.1" edgelet-core = { path = "../edgelet-core" } [target.'cfg(unix)'.dependencies] -hyperlocal = "0.4" +hyperlocal = "0.6" [target.'cfg(windows)'.dependencies] httparse = "1.2" mio = "0.6" -mio-named-pipes = "0.1" \ No newline at end of file +mio-named-pipes = "0.1" diff --git a/edgelet/edgelet-test-utils/src/json_connector.rs b/edgelet/edgelet-test-utils/src/json_connector.rs index 704350f1a80..9767a5ab8b5 100644 --- a/edgelet/edgelet-test-utils/src/json_connector.rs +++ b/edgelet/edgelet-test-utils/src/json_connector.rs @@ -3,11 +3,10 @@ use std::io::{self, Cursor, Read, Write}; use futures::{future, task, Future, Poll}; -use hyper::client::Service; -use hyper::Uri; +use hyper::client::connect::{Connect, Connected, Destination}; use serde::Serialize; use serde_json; -use tokio_io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite}; pub struct StaticStream { wrote: bool, @@ -53,37 +52,36 @@ impl AsyncWrite for StaticStream { } } -pub struct JsonConnector { - body: T, +pub struct JsonConnector { + body: Vec, } -impl JsonConnector { - pub fn new(body: T) -> JsonConnector { - JsonConnector { body } - } -} - -impl Service for JsonConnector { - type Request = Uri; - type Response = StaticStream; - type Error = io::Error; - type Future = Box>; - - fn call(&self, _req: Uri) -> Self::Future { - let json = serde_json::to_string(&self.body).unwrap(); - let response = format!( +impl JsonConnector { + pub fn new(body: &T) -> JsonConnector { + let body = serde_json::to_string(body).unwrap(); + let body = format!( "HTTP/1.1 200 OK\r\n\ Content-Type: application/json; charset=utf-8\r\n\ Content-Length: {}\r\n\ \r\n\ {}", - json.len(), - json - ); + body.len(), + body, + ).into(); - Box::new(future::ok(StaticStream { - wrote: false, - body: Cursor::new(response.into_bytes()), - })) + JsonConnector { body } + } +} + +impl Connect for JsonConnector { + type Transport = StaticStream; + type Error = io::Error; + type Future = Box + Send>; + + fn connect(&self, _dst: Destination) -> Self::Future { + Box::new(future::ok(( + StaticStream::new(self.body.clone()), + Connected::new(), + ))) } } diff --git a/edgelet/edgelet-test-utils/src/lib.rs b/edgelet/edgelet-test-utils/src/lib.rs index 7039acc8bd4..c68d05d790d 100644 --- a/edgelet/edgelet-test-utils/src/lib.rs +++ b/edgelet/edgelet-test-utils/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] extern crate edgelet_core; #[macro_use] @@ -19,7 +19,7 @@ extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; -extern crate tokio_io; +extern crate tokio; use std::net::TcpListener; diff --git a/edgelet/edgelet-test-utils/src/web/linux.rs b/edgelet/edgelet-test-utils/src/web/linux.rs index 7bde1b0cc47..612103b35d5 100644 --- a/edgelet/edgelet-test-utils/src/web/linux.rs +++ b/edgelet/edgelet-test-utils/src/web/linux.rs @@ -1,26 +1,38 @@ // Copyright (c) Microsoft. All rights reserved. use std::fs; -use std::sync::mpsc::Sender; +use std::io; +use std::os::unix::net::UnixListener as StdUnixListener; use futures::prelude::*; -use hyper::server::{const_service, service_fn, Request, Response}; -use hyper::Error as HyperError; -use hyperlocal::server::Http as UdsHttp; +use hyper::service::service_fn; +use hyper::{self, Body, Request, Response}; +use hyperlocal::server::{Http as UdsHttp, Incoming as UdsIncoming}; -pub fn run_uds_server(path: &str, handler: F, ready_channel: &Sender<()>) +pub fn run_uds_server(path: &str, handler: F) -> impl Future where - R: 'static + Future, - F: 'static + Fn(Request) -> R + Send + Sync, + F: 'static + Fn(Request) -> R + Clone + Send + Sync, + R: 'static + Future, Error = io::Error> + Send, { fs::remove_file(&path).unwrap_or(()); - let server = UdsHttp::new() - .bind(path, const_service(service_fn(handler))) - .unwrap(); + // Bind a listener synchronously, so that the caller's client will not fail to connect + // regardless of when the asynchronous server accepts the connection + let listener = StdUnixListener::bind(path).unwrap(); + let incoming = UdsIncoming::from_std(listener, &Default::default()).unwrap(); + let serve = UdsHttp::new().serve_incoming(incoming, move || service_fn(handler.clone())); - // signal that the server is ready to run - ready_channel.send(()).unwrap(); - - server.run().unwrap(); + serve.for_each(|connecting| { + connecting + .then(|connection| { + let connection = connection.unwrap(); + Ok::<_, hyper::Error>(connection) + }).flatten() + .map_err(|e| { + io::Error::new( + io::ErrorKind::Other, + format!("failed to serve connection: {}", e), + ) + }) + }) } diff --git a/edgelet/edgelet-test-utils/src/web/mod.rs b/edgelet/edgelet-test-utils/src/web/mod.rs index 098990d0a9f..985f36385dd 100644 --- a/edgelet/edgelet-test-utils/src/web/mod.rs +++ b/edgelet/edgelet-test-utils/src/web/mod.rs @@ -12,24 +12,30 @@ pub use self::linux::run_uds_server; #[cfg(windows)] pub use self::windows::run_pipe_server; -use std::sync::mpsc::Sender; - use futures::prelude::*; -use hyper::server::{const_service, service_fn, Http, Request, Response}; -use hyper::Error as HyperError; - -pub fn run_tcp_server(ip: &str, port: u16, handler: F, ready_channel: &Sender<()>) +use hyper::server::conn::Http; +use hyper::service::service_fn; +use hyper::{self, Body, Request, Response}; + +pub fn run_tcp_server( + ip: &str, + port: u16, + handler: F, +) -> impl Future where - R: 'static + Future, - F: 'static + Fn(Request) -> R, + F: 'static + Fn(Request) -> R + Clone + Send + Sync, + R: 'static + Future, Error = hyper::Error> + Send, { let addr = &format!("{}:{}", ip, port).parse().unwrap(); - let server = Http::new() - .bind(addr, const_service(service_fn(handler))) - .unwrap(); - // signal that the server is ready to run - ready_channel.send(()).unwrap(); - - server.run().unwrap(); + let serve = Http::new() + .serve_addr(addr, move || service_fn(handler.clone())) + .unwrap(); + serve.for_each(|connecting| { + connecting + .then(|connection| { + let connection = connection.unwrap(); + Ok::<_, hyper::Error>(connection) + }).flatten() + }) } diff --git a/edgelet/edgelet-test-utils/src/web/windows.rs b/edgelet/edgelet-test-utils/src/web/windows.rs index 98118afcf20..3323271217e 100644 --- a/edgelet/edgelet-test-utils/src/web/windows.rs +++ b/edgelet/edgelet-test-utils/src/web/windows.rs @@ -77,7 +77,7 @@ fn wait_readable(poll: &Poll, events: &mut Events) { fn get_content_length<'a>(headers: &'a [httparse::Header<'a>]) -> Option { for header in headers { - if header.name == "Content-Length" { + if header.name.eq_ignore_ascii_case("Content-Length") { return Some(str::from_utf8(header.value).unwrap().parse().unwrap()); } } diff --git a/edgelet/edgelet-utils/Cargo.toml b/edgelet/edgelet-utils/Cargo.toml index 42fdadc6742..8af8353f465 100644 --- a/edgelet/edgelet-utils/Cargo.toml +++ b/edgelet/edgelet-utils/Cargo.toml @@ -6,10 +6,10 @@ publish = false [dependencies] failure = "0.1" -futures = "0.1" log = "0.4" serde = "1.0" serde_json = "1.0" [dev_dependencies] +futures = "0.1" serde_derive = "1.0" diff --git a/edgelet/edgelet-utils/src/lib.rs b/edgelet/edgelet-utils/src/lib.rs index b5f3b5832d9..7744b22e733 100644 --- a/edgelet/edgelet-utils/src/lib.rs +++ b/edgelet/edgelet-utils/src/lib.rs @@ -1,9 +1,10 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] #[macro_use] extern crate failure; +#[cfg(test)] extern crate futures; #[macro_use] extern crate log; diff --git a/edgelet/edgelet-utils/src/ser_de.rs b/edgelet/edgelet-utils/src/ser_de.rs index 2c8979a2df4..09336092bd3 100644 --- a/edgelet/edgelet-utils/src/ser_de.rs +++ b/edgelet/edgelet-utils/src/ser_de.rs @@ -5,10 +5,8 @@ use std::marker::PhantomData; use std::result::Result as StdResult; use std::str::FromStr; -use serde::{ - de::{self, Deserialize, DeserializeOwned, Deserializer, MapAccess, Visitor}, - ser::Serialize, -}; +use serde::de::{self, Deserialize, DeserializeOwned, Deserializer, MapAccess, Visitor}; +use serde::ser::Serialize; use serde_json; use error::Result; diff --git a/edgelet/hsm-rs/src/crypto.rs b/edgelet/hsm-rs/src/crypto.rs index 2a818d86e07..c11163a9ec7 100644 --- a/edgelet/hsm-rs/src/crypto.rs +++ b/edgelet/hsm-rs/src/crypto.rs @@ -36,6 +36,9 @@ pub struct Crypto { interface: HSM_CLIENT_CRYPTO_INTERFACE_TAG, } +// Handles don't have thread-affinity +unsafe impl Send for Crypto {} + impl Drop for Crypto { fn drop(&mut self) { if let Some(f) = self.interface.hsm_client_crypto_destroy { diff --git a/edgelet/hsm-rs/src/lib.rs b/edgelet/hsm-rs/src/lib.rs index 044db2b3bf2..09b71a31ed4 100644 --- a/edgelet/hsm-rs/src/lib.rs +++ b/edgelet/hsm-rs/src/lib.rs @@ -1,4 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. + +#![deny(unused_extern_crates, warnings)] + #[macro_use] extern crate failure; extern crate hsm_sys; diff --git a/edgelet/hsm-rs/src/tpm.rs b/edgelet/hsm-rs/src/tpm.rs index e548a55bed5..42e6deadd50 100644 --- a/edgelet/hsm-rs/src/tpm.rs +++ b/edgelet/hsm-rs/src/tpm.rs @@ -19,6 +19,9 @@ pub struct Tpm { interface: HSM_CLIENT_TPM_INTERFACE, } +// Handles don't have thread-affinity +unsafe impl Send for Tpm {} + // HSM TPM impl Drop for Tpm { diff --git a/edgelet/hsm-sys/src/lib.rs b/edgelet/hsm-sys/src/lib.rs index 928be717a45..6c750e677d1 100644 --- a/edgelet/hsm-sys/src/lib.rs +++ b/edgelet/hsm-sys/src/lib.rs @@ -1,4 +1,5 @@ // Copyright (c) Microsoft. All rights reserved. + //! iot-hsm-sys //! Rust FFI to C library interface //! Based off of https://github.com/Azure/azure-iot-hsm-c/inc/hsm_client_data.h @@ -6,9 +7,8 @@ //! //! Intitial version created through bindgen https://docs.rs/bindgen/ -#![allow(non_upper_case_globals)] -#![allow(non_camel_case_types)] -#![allow(non_snake_case)] +#![deny(unused_extern_crates, warnings)] +#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals)] use std::os::raw::{c_char, c_int, c_uchar, c_void}; diff --git a/edgelet/hyper-named-pipe/Cargo.toml b/edgelet/hyper-named-pipe/Cargo.toml index f6a4a96ddea..25bed5ff45a 100644 --- a/edgelet/hyper-named-pipe/Cargo.toml +++ b/edgelet/hyper-named-pipe/Cargo.toml @@ -8,10 +8,8 @@ publish = false failure = "0.1" futures = "0.1" hex = "0.3" -hyper = "0.11" -tokio-core = "0.1" +hyper = "0.12" tokio-named-pipe = { path = "../tokio-named-pipe" } -tokio-service = "0.1" url = "1.7" edgelet-utils = { path = "../edgelet-utils" } @@ -19,5 +17,7 @@ edgelet-utils = { path = "../edgelet-utils" } [dev-dependencies] httparse = "1.2" rand = "0.4" +tokio = "0.1.8" +typed-headers = "0.1" edgelet-test-utils = { path = "../edgelet-test-utils" } diff --git a/edgelet/hyper-named-pipe/src/lib.rs b/edgelet/hyper-named-pipe/src/lib.rs index 9b3d946b409..245ab7989d7 100644 --- a/edgelet/hyper-named-pipe/src/lib.rs +++ b/edgelet/hyper-named-pipe/src/lib.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] #![cfg(windows)] +#![deny(unused_extern_crates, warnings)] #[macro_use] extern crate failure; @@ -12,9 +12,7 @@ extern crate edgelet_utils; extern crate futures; extern crate hex; extern crate hyper; -extern crate tokio_core; extern crate tokio_named_pipe; -extern crate tokio_service; extern crate url; pub mod error; @@ -24,9 +22,7 @@ use std::io; use futures::future::FutureResult; use futures::IntoFuture; -use hyper::Uri as HyperUri; -use tokio_core::reactor::Handle; -use tokio_service::Service; +use hyper::client::connect::{Connect, Connected, Destination}; use tokio_named_pipe::PipeStream; @@ -35,25 +31,22 @@ pub use uri::Uri; pub const NAMED_PIPE_SCHEME: &str = "npipe"; -pub struct PipeConnector(Handle); +pub struct PipeConnector; -impl PipeConnector { - pub fn new(handle: Handle) -> Self { - PipeConnector(handle) - } -} - -impl Service for PipeConnector { - type Request = HyperUri; - type Response = PipeStream; +impl Connect for PipeConnector { + type Transport = PipeStream; type Error = io::Error; - type Future = FutureResult; + type Future = FutureResult<(Self::Transport, Connected), Self::Error>; - fn call(&self, uri: HyperUri) -> Self::Future { - Uri::get_pipe_path(&uri) + fn connect(&self, dst: Destination) -> Self::Future { + Uri::get_pipe_path(&dst) .map_err(|_err| { - io::Error::new(io::ErrorKind::InvalidInput, format!("Invalid uri {}", uri)) - }).and_then(|path| PipeStream::connect(path, &self.0, None)) + io::Error::new( + io::ErrorKind::InvalidInput, + format!("Invalid destination {:?}", dst), + ) + }).and_then(|path| PipeStream::connect(path, None)) + .map(|stream| (stream, Connected::new())) .into_future() } } diff --git a/edgelet/hyper-named-pipe/src/uri.rs b/edgelet/hyper-named-pipe/src/uri.rs index e2f1a571b1f..7e9414ee5ef 100644 --- a/edgelet/hyper-named-pipe/src/uri.rs +++ b/edgelet/hyper-named-pipe/src/uri.rs @@ -3,6 +3,7 @@ use std::str; use hex::{decode, encode}; +use hyper::client::connect::Destination; use hyper::Uri as HyperUri; use url::Url; @@ -38,20 +39,23 @@ impl Uri { } } - pub fn get_pipe_path(uri: &HyperUri) -> Result { - if uri.scheme() != Some(NAMED_PIPE_SCHEME) { + pub fn get_pipe_path(dst: &Destination) -> Result { + Uri::get_pipe_path_from_parts(dst.scheme(), dst.host()) + } + + fn get_pipe_path_from_parts(scheme: &str, host: &str) -> Result { + if scheme != NAMED_PIPE_SCHEME { Err(ErrorKind::InvalidUrlScheme)? } else { - uri.host() - .map(|h| h.trim()) - .and_then(|h| if h.is_empty() { None } else { Some(h) }) - .ok_or_else(|| Error::from(ErrorKind::MissingUrlHost)) - .and_then(|h| decode(h).map_err(Error::from)) - .and_then(|bytes| { - str::from_utf8(bytes.as_slice()) - .map_err(Error::from) - .map(|s| s.to_owned()) - }) + let host = host.trim(); + if host.is_empty() { + return Err(Error::from(ErrorKind::MissingUrlHost)); + } + + let bytes = decode(host).map_err(Error::from)?; + + let s = str::from_utf8(bytes.as_slice()).map_err(Error::from)?; + Ok(s.to_owned()) } } } @@ -123,29 +127,33 @@ mod tests { #[test] fn uri_host_scheme() { - let uri = "foo://boo".parse().unwrap(); - assert!(Uri::get_pipe_path(&uri).is_err()); - } - - #[test] - fn uri_host_empty() { - let uri = "npipe:// /".parse().unwrap(); - assert!(Uri::get_pipe_path(&uri).is_err()); + let uri: HyperUri = "foo://boo".parse().unwrap(); + assert!( + Uri::get_pipe_path_from_parts(uri.scheme_part().unwrap().as_str(), uri.host().unwrap()) + .is_err() + ); } #[test] fn uri_host_decode() { - let uri = "npipe://123/".parse().unwrap(); - assert!(Uri::get_pipe_path(&uri).is_err()); + let uri: HyperUri = "npipe://123/".parse().unwrap(); + assert!( + Uri::get_pipe_path_from_parts(uri.scheme_part().unwrap().as_str(), uri.host().unwrap()) + .is_err() + ); } #[test] fn uri_host() { - let uri = "npipe://5c5c2e5c706970655c646f636b65725f656e67696e65/containers/json?all=true" - .parse() - .unwrap(); + let uri: HyperUri = + "npipe://5c5c2e5c706970655c646f636b65725f656e67696e65/containers/json?all=true" + .parse() + .unwrap(); assert_eq!( - &Uri::get_pipe_path(&uri).unwrap(), + &Uri::get_pipe_path_from_parts( + uri.scheme_part().unwrap().as_str(), + uri.host().unwrap() + ).unwrap(), "\\\\.\\pipe\\docker_engine" ); } diff --git a/edgelet/hyper-named-pipe/tests/smoke.rs b/edgelet/hyper-named-pipe/tests/smoke.rs index 155313c3bb7..b7ac5b5fcae 100644 --- a/edgelet/hyper-named-pipe/tests/smoke.rs +++ b/edgelet/hyper-named-pipe/tests/smoke.rs @@ -7,7 +7,8 @@ extern crate futures; extern crate httparse; extern crate hyper; extern crate rand; -extern crate tokio_core; +extern crate tokio; +extern crate typed_headers; extern crate edgelet_test_utils; extern crate hyper_named_pipe; @@ -18,10 +19,11 @@ use std::thread; use futures::future::Future; use futures::Stream; use httparse::Request; -use hyper::header::{ContentLength, ContentType}; -use hyper::{Client as HyperClient, Method, Request as HyperRequest, StatusCode}; +use hyper::{ + Body, Client as HyperClient, Method, Request as HyperRequest, StatusCode, Uri as HyperUri, +}; use rand::Rng; -use tokio_core::reactor::Core; +use typed_headers::{mime, ContentLength, ContentType, HeaderMapExt}; use edgelet_test_utils::run_pipe_server; use hyper_named_pipe::{PipeConnector, Uri}; @@ -51,15 +53,15 @@ fn get() { // wait for server to get ready receiver.recv().unwrap(); - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::configure() - .connector(PipeConnector::new(core.handle())) - .build(&core.handle()); + let hyper_client = HyperClient::builder().build::<_, Body>(PipeConnector); // make a get request let task = hyper_client.get(url.into()); - let response = core.run(task).unwrap(); - assert_eq!(response.status(), StatusCode::Ok); + let response = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); + assert_eq!(response.status(), StatusCode::OK); } const GET_RESPONSE: &str = "The answer is 42"; @@ -89,22 +91,22 @@ fn get_with_body() { // wait for server to get ready receiver.recv().unwrap(); - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::configure() - .connector(PipeConnector::new(core.handle())) - .build(&core.handle()); + let hyper_client = HyperClient::builder().build::<_, Body>(PipeConnector); // make a get request let task = hyper_client .get(url.into()) .and_then(|res| { - assert_eq!(StatusCode::Ok, res.status()); - res.body().concat2() + assert_eq!(StatusCode::OK, res.status()); + res.into_body().concat2() }).map(|body| { assert_eq!(GET_RESPONSE, &String::from_utf8_lossy(body.as_ref())); }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } const POST_BODY: &str = r#"{"donuts":"yes"}"#; @@ -121,7 +123,7 @@ fn post_handler(_req: &Request, body: Option>) -> String { fn post() { let (sender, receiver) = channel(); let path = make_path(); - let url = make_url(&path); + let url: HyperUri = make_url(&path).into(); thread::spawn(move || { run_pipe_server(&path, post_handler, &sender); @@ -130,20 +132,25 @@ fn post() { // wait for server to get ready receiver.recv().unwrap(); - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::configure() - .connector(PipeConnector::new(core.handle())) - .build(&core.handle()); + let hyper_client = HyperClient::builder().build::<_, Body>(PipeConnector); // make a post request - let mut req = HyperRequest::new(Method::Post, url.into()); - req.headers_mut().set(ContentType::json()); - req.headers_mut().set(ContentLength(POST_BODY.len() as u64)); - req.set_body(POST_BODY); + let mut req = HyperRequest::builder() + .method(Method::POST) + .uri(url) + .body(POST_BODY.into()) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&ContentLength(POST_BODY.len() as u64)); let task = hyper_client.request(req).map(|res| { - assert_eq!(StatusCode::Ok, res.status()); + assert_eq!(StatusCode::OK, res.status()); }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } diff --git a/edgelet/iotedge/Cargo.toml b/edgelet/iotedge/Cargo.toml index 3e9c0c6ee99..3538504de10 100644 --- a/edgelet/iotedge/Cargo.toml +++ b/edgelet/iotedge/Cargo.toml @@ -14,12 +14,9 @@ clap = "2.31" failure = "0.1" failure_derive = "0.1" futures = "0.1" -hyper = "0.11" tabwriter = "1.0" -tokio-core = "0.1" -tokio-io = "0.1" +tokio = "0.1" url = "1.7" edgelet-core = { path = "../edgelet-core" } edgelet-http-mgmt = { path = "../edgelet-http-mgmt" } -management = { path = "../management" } diff --git a/edgelet/iotedge/src/lib.rs b/edgelet/iotedge/src/lib.rs index 6fd2e10bd7f..9815cf270ac 100644 --- a/edgelet/iotedge/src/lib.rs +++ b/edgelet/iotedge/src/lib.rs @@ -1,5 +1,12 @@ // Copyright (c) Microsoft. All rights reserved. +#![deny(unused_extern_crates, warnings)] +// Remove this when clippy stops warning about old-style `allow()`, +// which can only be silenced by enabling a feature and thus requires nightly +// +// Ref: https://github.com/rust-lang-nursery/rust-clippy/issues/3159#issuecomment-420530386 +#![allow(renamed_and_removed_lints)] + extern crate bytes; extern crate chrono; extern crate chrono_humanize; @@ -13,7 +20,7 @@ extern crate failure_derive; #[macro_use] extern crate futures; extern crate tabwriter; -extern crate tokio_io; +extern crate tokio; extern crate url; use futures::Future; @@ -33,7 +40,7 @@ pub use unknown::Unknown; pub use version::Version; pub trait Command { - type Future: Future; + type Future: Future + Send; fn execute(&mut self) -> Self::Future; } diff --git a/edgelet/iotedge/src/list.rs b/edgelet/iotedge/src/list.rs index c8cc34bd20e..1f6ef7c6e40 100644 --- a/edgelet/iotedge/src/list.rs +++ b/edgelet/iotedge/src/list.rs @@ -1,9 +1,8 @@ // Copyright (c) Microsoft. All rights reserved. -use std::cell::RefCell; use std::fmt::Display; use std::io::Write; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use chrono::{Duration, Utc}; use chrono_humanize::{Accuracy, HumanTime, Tense}; @@ -16,7 +15,7 @@ use Command; pub struct List { runtime: M, - output: Arc>>, + output: Arc>>, } impl List @@ -27,7 +26,7 @@ where let tab = TabWriter::new(output).minwidth(15); List { runtime, - output: Arc::new(RefCell::new(tab)), + output: Arc::new(Mutex::new(tab)), } } } @@ -39,9 +38,9 @@ where M::Config: Display, M::Error: Into, ::Error: Into, - W: 'static + Write, + W: 'static + Write + Send, { - type Future = Box>; + type Future = Box + Send>; fn execute(&mut self) -> Self::Future { let write = self.output.clone(); @@ -55,7 +54,7 @@ where future::join_all(futures) .map_err(|e| e.into()) .and_then(move |states| { - let mut w = write.borrow_mut(); + let mut w = write.lock().unwrap(); writeln!(w, "NAME\tSTATUS\tDESCRIPTION\tCONFIG")?; for (module, state) in modules.iter().zip(states) { writeln!( diff --git a/edgelet/iotedge/src/logs.rs b/edgelet/iotedge/src/logs.rs index aeb16ee665f..01271d0eee1 100644 --- a/edgelet/iotedge/src/logs.rs +++ b/edgelet/iotedge/src/logs.rs @@ -6,8 +6,9 @@ use std::io::{self, Write}; use bytes::{Buf, BufMut, Bytes, BytesMut, IntoBuf}; use edgelet_core::{LogOptions, ModuleRuntime}; use futures::prelude::*; -use tokio_io::codec::length_delimited::{self, FramedRead}; -use tokio_io::AsyncRead; +use tokio::codec::length_delimited; +use tokio::codec::FramedRead; +use tokio::io::AsyncRead; use error::{Error, ErrorKind}; use Command; @@ -32,7 +33,7 @@ impl Command for Logs where M: 'static + ModuleRuntime + Clone, { - type Future = Box>; + type Future = Box + Send>; fn execute(&mut self) -> Self::Future { let id = self.id.clone(); @@ -71,7 +72,7 @@ where /// /// The following set of structs converts a Stream<&[u8]> into a Stream /// by implementing AsyncRead on Stream<&[u8]> and then using the length_delimited -/// decoder in tokio-io to emit BytesMut with complete frames. The LogChunk +/// decoder in tokio to emit BytesMut with complete frames. The LogChunk /// is then constructed from these BytesMuts #[derive(Debug, PartialEq)] @@ -83,7 +84,7 @@ enum LogChunk { } struct LogDecode { - inner: FramedRead, + inner: FramedRead, } impl LogDecode { diff --git a/edgelet/iotedge/src/main.rs b/edgelet/iotedge/src/main.rs index ef501e920aa..550aa6b81f0 100644 --- a/edgelet/iotedge/src/main.rs +++ b/edgelet/iotedge/src/main.rs @@ -1,15 +1,14 @@ // Copyright (c) Microsoft. All rights reserved. +#![deny(unused_extern_crates, warnings)] + #[macro_use] extern crate clap; extern crate edgelet_core; extern crate edgelet_http_mgmt; extern crate failure; -extern crate futures; -extern crate hyper; extern crate iotedge; -extern crate management; -extern crate tokio_core; +extern crate tokio; extern crate url; use std::io; @@ -21,7 +20,6 @@ use edgelet_core::{LogOptions, LogTail}; use edgelet_http_mgmt::ModuleClient; use failure::Fail; use iotedge::*; -use tokio_core::reactor::Core; use url::Url; #[cfg(unix)] @@ -46,7 +44,6 @@ fn main() { } fn run() -> Result<(), Error> { - let mut core = Core::new()?; let default_uri = option_env!("IOTEDGE_HOST").unwrap_or(MGMT_URI); let matches = App::new(crate_name!()) @@ -101,11 +98,13 @@ fn run() -> Result<(), Error> { .value_of("host") .map(|h| Url::parse(h).map_err(Error::from)) .unwrap_or_else(|| Err(Error::from(ErrorKind::NoHost)))?; - let runtime = ModuleClient::new(&url, &core.handle())?; + let runtime = ModuleClient::new(&url)?; + + let mut tokio_runtime = tokio::runtime::Runtime::new()?; match matches.subcommand() { - ("list", Some(_args)) => core.run(List::new(runtime, io::stdout()).execute()), - ("restart", Some(args)) => core.run( + ("list", Some(_args)) => tokio_runtime.block_on(List::new(runtime, io::stdout()).execute()), + ("restart", Some(args)) => tokio_runtime.block_on( Restart::new( args.value_of("MODULE").unwrap().to_string(), runtime, @@ -120,9 +119,9 @@ fn run() -> Result<(), Error> { .and_then(|a| a.parse::().ok()) .unwrap_or_default(); let options = LogOptions::new().with_follow(follow).with_tail(tail); - core.run(Logs::new(id, options, runtime).execute()) + tokio_runtime.block_on(Logs::new(id, options, runtime).execute()) } - ("version", Some(_args)) => core.run(Version::new().execute()), - (command, _) => core.run(Unknown::new(command.to_string()).execute()), + ("version", Some(_args)) => tokio_runtime.block_on(Version::new().execute()), + (command, _) => tokio_runtime.block_on(Unknown::new(command.to_string()).execute()), } } diff --git a/edgelet/iotedge/src/restart.rs b/edgelet/iotedge/src/restart.rs index 54a32ddf76f..ebadb6787c4 100644 --- a/edgelet/iotedge/src/restart.rs +++ b/edgelet/iotedge/src/restart.rs @@ -1,8 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. -use std::cell::RefCell; use std::io::Write; -use std::sync::Arc; +use std::sync::{Arc, Mutex}; use edgelet_core::ModuleRuntime; use futures::Future; @@ -13,7 +12,7 @@ use Command; pub struct Restart { id: String, runtime: M, - output: Arc>, + output: Arc>, } impl Restart { @@ -21,7 +20,7 @@ impl Restart { Restart { id, runtime, - output: Arc::new(RefCell::new(output)), + output: Arc::new(Mutex::new(output)), } } } @@ -30,9 +29,9 @@ impl Command for Restart where M: 'static + ModuleRuntime + Clone, M::Error: Into, - W: 'static + Write, + W: 'static + Write + Send, { - type Future = Box>; + type Future = Box + Send>; fn execute(&mut self) -> Self::Future { let id = self.id.clone(); @@ -42,7 +41,7 @@ where .restart(&id) .map_err(|e| e.into()) .and_then(move |_| { - let mut w = write.borrow_mut(); + let mut w = write.lock().unwrap(); writeln!(w, "{}", id)?; Ok(()) }); diff --git a/edgelet/iotedged/Cargo.toml b/edgelet/iotedged/Cargo.toml index eb9da0aa0b0..e7e9dd1757e 100644 --- a/edgelet/iotedged/Cargo.toml +++ b/edgelet/iotedged/Cargo.toml @@ -11,15 +11,16 @@ config = "0.8" env_logger = "0.5" failure = "0.1" futures = "0.1" -hyper = "0.11" -hyper-tls = "0.1" +http = "0.1" +hyper = "0.12" +hyper-tls = "0.3" log = "0.4" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" sha2 = "0.7.0" -tokio-core = "0.1" -tokio-signal = "0.1" +tokio = "0.1.8" +tokio-signal = "0.2" url = "1.7" url_serde = "0.2" diff --git a/edgelet/iotedged/src/error.rs b/edgelet/iotedged/src/error.rs index 6a04fc5dcb4..12e0ae56a1c 100644 --- a/edgelet/iotedged/src/error.rs +++ b/edgelet/iotedged/src/error.rs @@ -16,7 +16,7 @@ use edgelet_hsm::Error as SoftHsmError; use edgelet_http::Error as HttpError; use failure::{Backtrace, Context, Fail}; use hsm::Error as HardHsmError; -use hyper::error::UriError; +use http; use hyper::Error as HyperError; use hyper_tls::Error as HyperTlsError; use iothubservice::error::Error as IotHubError; @@ -238,8 +238,8 @@ impl From for Error { } } -impl From for Error { - fn from(error: UriError) -> Error { +impl From for Error { + fn from(error: http::uri::InvalidUri) -> Error { Error { inner: error.context(ErrorKind::Parse), } diff --git a/edgelet/iotedged/src/lib.rs b/edgelet/iotedged/src/lib.rs index b0e1d0edc6b..f81c546176c 100644 --- a/edgelet/iotedged/src/lib.rs +++ b/edgelet/iotedged/src/lib.rs @@ -1,6 +1,11 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] +// Remove this when clippy stops warning about old-style `allow()`, +// which can only be silenced by enabling a feature and thus requires nightly +// +// Ref: https://github.com/rust-lang-nursery/rust-clippy/issues/3159#issuecomment-420530386 +#![allow(renamed_and_removed_lints)] extern crate base64; #[macro_use] @@ -22,6 +27,7 @@ extern crate env_logger; extern crate failure; extern crate futures; extern crate hsm; +extern crate http; extern crate hyper; extern crate hyper_tls; extern crate iothubservice; @@ -35,7 +41,7 @@ extern crate serde_derive; extern crate serde_json; #[cfg(test)] extern crate tempdir; -extern crate tokio_core; +extern crate tokio; extern crate tokio_signal; extern crate url; extern crate url_serde; @@ -61,7 +67,7 @@ use std::collections::HashMap; use std::env; use std::fs; use std::fs::{DirBuilder, File}; -use std::io::Write; +use std::io::{self, Write}; use std::path::{Path, PathBuf}; use docker::models::HostConfig; @@ -75,27 +81,24 @@ use edgelet_core::{ModuleRuntime, ModuleSpec}; use edgelet_docker::{DockerConfig, DockerModuleRuntime}; use edgelet_hsm::tpm::{TpmKey, TpmKeyStore}; use edgelet_hsm::Crypto; -use edgelet_http::client::Client as HttpClient; +use edgelet_http::client::{Client as HttpClient, ClientImpl}; use edgelet_http::logging::LoggingService; use edgelet_http::{ApiVersionService, HyperExt, MaybeProxyClient, API_VERSION}; use edgelet_http_mgmt::ManagementService; use edgelet_http_workload::WorkloadService; use edgelet_iothub::{HubIdentityManager, SasTokenSource}; -use futures::future; use futures::future::Either; use futures::sync::oneshot::{self, Receiver}; -use futures::Future; +use futures::{future, Future}; use hsm::tpm::Tpm; use hsm::ManageTpmKeys; -use hyper::client::Service; -use hyper::server::Http; -use hyper::{Error as HyperError, Request, Response, Uri}; +use hyper::server::conn::Http; +use hyper::Uri; use iothubservice::DeviceClient; use provisioning::provisioning::{ BackupProvisioning, DpsProvisioning, ManualProvisioning, Provision, ProvisioningResult, }; use sha2::{Digest, Sha256}; -use tokio_core::reactor::{Core, Handle}; use url::Url; use settings::{Dps, Manual, Provisioning, Settings, DEFAULT_CONNECTION_STRING}; @@ -178,28 +181,21 @@ const IOTEDGED_COMMONNAME: &str = "iotedged workload ca"; pub struct Main { settings: Settings, - reactor: Core, } impl Main { pub fn new(settings: Settings) -> Result { - let reactor = Core::new()?; - let main = Main { settings, reactor }; + let main = Main { settings }; Ok(main) } - pub fn handle(&self) -> Handle { - self.reactor.handle() - } - pub fn run_until(self, shutdown_signal: F) -> Result<(), Error> where - F: Future + 'static, + F: Future + Send + 'static, { - let Main { - settings, - reactor: mut core, - } = self; + let Main { settings } = self; + + let mut tokio_runtime = tokio::runtime::Runtime::new()?; if let Provisioning::Manual(ref manual) = settings.provisioning() { if manual.device_connection_string() == DEFAULT_CONNECTION_STRING { @@ -207,17 +203,16 @@ impl Main { } } - let handle: Handle = core.handle().clone(); - let hyper_client = MaybeProxyClient::new(&handle, get_proxy_uri()?)?; + let hyper_client = MaybeProxyClient::new(get_proxy_uri()?)?; info!( "Using runtime network id {}", settings.moby_runtime().network() ); - let runtime = DockerModuleRuntime::new(settings.moby_runtime().uri(), &handle)? + let runtime = DockerModuleRuntime::new(settings.moby_runtime().uri())? .with_network_id(settings.moby_runtime().network().to_string()); - init_docker_runtime(&runtime, &mut core)?; + init_docker_runtime(&runtime, &mut tokio_runtime)?; info!( "Configuring {} as the home directory.", @@ -258,19 +253,18 @@ impl Main { EDGE_SETTINGS_STATE_FILENAME, &settings, &runtime, - &mut core, &crypto, + &mut tokio_runtime, )?; info!("Provisioning edge device..."); match settings.provisioning() { Provisioning::Manual(manual) => { let (key_store, provisioning_result, root_key) = - manual_provision(&manual, &mut core)?; + manual_provision(&manual, &mut tokio_runtime)?; info!("Finished provisioning edge device."); start_api( &settings, - core, hyper_client, &runtime, &key_store, @@ -278,16 +272,21 @@ impl Main { root_key, shutdown_signal, &crypto, + tokio_runtime, )?; } Provisioning::Dps(dps) => { let dps_path = cache_subdir_path.join(EDGE_PROVISIONING_BACKUP_FILENAME); - let (key_store, provisioning_result, root_key) = - dps_provision(&dps, hyper_client.clone(), &mut core, dps_path, &runtime)?; + let (key_store, provisioning_result, root_key, runtime) = dps_provision( + &dps, + hyper_client.clone(), + dps_path, + runtime, + &mut tokio_runtime, + )?; info!("Finished provisioning edge device."); start_api( &settings, - core, hyper_client, &runtime, &key_store, @@ -295,6 +294,7 @@ impl Main { root_key, shutdown_signal, &crypto, + tokio_runtime, )?; } }; @@ -351,12 +351,13 @@ fn check_settings_state( filename: &str, settings: &Settings, runtime: &M, - core: &mut Core, crypto: &C, + tokio_runtime: &mut tokio::runtime::Runtime, ) -> Result<(), Error> where M: ModuleRuntime, - M::Error: Into, + ::Error: Into, + ::RemoveAllFuture: 'static, C: MasterEncryptionKey + CreateCertificate, { info!("Detecting if configuration file has changed..."); @@ -377,7 +378,14 @@ where }; } if reconfig_reqd { - reconfigure(subdir_path, filename, settings, runtime, crypto, core)?; + reconfigure( + subdir_path, + filename, + settings, + runtime, + crypto, + tokio_runtime, + )?; } Ok(()) } @@ -388,16 +396,17 @@ fn reconfigure( settings: &Settings, runtime: &M, crypto: &C, - core: &mut Core, + tokio_runtime: &mut tokio::runtime::Runtime, ) -> Result<(), Error> where M: ModuleRuntime, - M::Error: Into, + ::Error: Into, + ::RemoveAllFuture: 'static, C: MasterEncryptionKey + CreateCertificate, { // Remove all edge containers and destroy the cache (settings and dps backup) info!("Removing all modules..."); - core.run(runtime.remove_all().map_err(|err| err.into()))?; + tokio_runtime.block_on(runtime.remove_all().map_err(|err| err.into()))?; info!("Finished removing modules."); // Ignore errors from this operation because we could be recovering from a previous bad @@ -422,28 +431,30 @@ where } #[cfg_attr(feature = "cargo-clippy", allow(too_many_arguments))] -fn start_api( +fn start_api( settings: &Settings, - mut core: Core, - hyper_client: S, + hyper_client: HC, runtime: &DockerModuleRuntime, key_store: &DerivedKeyStore, provisioning_result: &ProvisioningResult, root_key: K, shutdown_signal: F, crypto: &C, + mut tokio_runtime: tokio::runtime::Runtime, ) -> Result<(), Error> where - F: Future + 'static, - S: 'static + Service, - K: 'static + Sign + Clone, + F: Future + Send + 'static, + HC: 'static + ClientImpl, + K: 'static + Sign + Clone + Send + Sync, C: 'static + CreateCertificate + Decrypt + Encrypt + GetTrustBundle + MasterEncryptionKey - + Clone, + + Clone + + Send + + Sync, { let hub_name = provisioning_result.hub_name(); let device_id = provisioning_result.device_id(); @@ -461,23 +472,16 @@ where let (mgmt_tx, mgmt_rx) = oneshot::channel(); let (work_tx, work_rx) = oneshot::channel(); - let mgmt = start_management(&settings, &core.handle(), &runtime, &id_man, mgmt_rx)?; + let mgmt = start_management(&settings, &runtime, &id_man, mgmt_rx); - let workload = start_workload( - &settings, - key_store, - &core.handle(), - &runtime, - work_rx, - crypto, - )?; + let workload = start_workload(&settings, key_store, &runtime, work_rx, crypto); let (runt_tx, runt_rx) = oneshot::channel(); let edge_rt = start_runtime(&runtime, &id_man, &hub_name, &device_id, &settings, runt_rx)?; // Wait for the watchdog to finish, and then send signal to the workload and management services. // This way the edgeAgent can finish shutting down all modules. - let edge_rt_with_cleanup = edge_rt.and_then(|_| { + let edge_rt_with_cleanup = edge_rt.map_err(Into::into).and_then(|_| { mgmt_tx.send(()).unwrap_or(()); work_tx.send(()).unwrap_or(()); future::ok(()) @@ -488,24 +492,37 @@ where // Signal the watchdog to shutdown runt_tx.send(()).unwrap_or(()); }); - - core.handle().spawn(shutdown); - - core.run(mgmt.join3(workload, edge_rt_with_cleanup))?; + tokio_runtime.spawn(shutdown); + + let services = mgmt + .join3(workload, edge_rt_with_cleanup) + .then(|result| match result { + Ok(((), (), ())) => Ok(()), + Err(err) => { + error!("{}", err); + Err(()) + } + }); + tokio_runtime + .block_on(services) + .map_err(|()| io::Error::new(io::ErrorKind::Other, "an error occurred"))?; Ok(()) } -fn init_docker_runtime(runtime: &DockerModuleRuntime, core: &mut Core) -> Result<(), Error> { +fn init_docker_runtime( + runtime: &DockerModuleRuntime, + tokio_runtime: &mut tokio::runtime::Runtime, +) -> Result<(), Error> { info!("Initializing the module runtime..."); - core.run(runtime.init())?; + tokio_runtime.block_on(runtime.init())?; info!("Finished initializing the module runtime."); Ok(()) } fn manual_provision( provisioning: &Manual, - core: &mut Core, + tokio_runtime: &mut tokio::runtime::Runtime, ) -> Result<(DerivedKeyStore, ProvisioningResult, MemoryKey), Error> { let manual = ManualProvisioning::new(provisioning.device_connection_string())?; let memory_hsm = MemoryKeyStore::new(); @@ -521,19 +538,19 @@ fn manual_provision( Ok((derived_key_store, prov_result, k)) }) }); - core.run(provision) + tokio_runtime.block_on(provision) } -fn dps_provision( +fn dps_provision( provisioning: &Dps, - hyper_client: S, - core: &mut Core, + hyper_client: HC, backup_path: PathBuf, - runtime: &M, -) -> Result<(DerivedKeyStore, ProvisioningResult, TpmKey), Error> + runtime: M, + tokio_runtime: &mut tokio::runtime::Runtime, +) -> Result<(DerivedKeyStore, ProvisioningResult, TpmKey, M), Error> where - S: 'static + Service, - M: ModuleRuntime, + HC: 'static + ClientImpl, + M: ModuleRuntime + Send + 'static, M::Error: Into, { let tpm = Tpm::new().map_err(Error::from)?; @@ -563,35 +580,35 @@ where let remove = runtime .remove_all() .map_err(|err| err.into()) - .map(|_| prov_result); + .map(|_| (prov_result, runtime)); Either::A(remove) } else { - Either::B(future::ok(prov_result)) + Either::B(future::ok((prov_result, runtime))) } - }).and_then(move |prov_result| { + }).and_then(move |(prov_result, runtime)| { tpm_hsm .get(&KeyIdentity::Device, "primary") .map_err(Error::from) .and_then(|k| { let derived_key_store = DerivedKeyStore::new(k.clone()); - Ok((derived_key_store, prov_result, k)) + Ok((derived_key_store, prov_result, k, runtime)) }) }); - core.run(provision) + tokio_runtime.block_on(provision) } -fn start_runtime( +fn start_runtime( runtime: &DockerModuleRuntime, - id_man: &HubIdentityManager, S, K>, + id_man: &HubIdentityManager, HC, K>, hostname: &str, device_id: &str, settings: &Settings, shutdown: Receiver<()>, ) -> Result, Error> where - K: 'static + Sign + Clone, - S: 'static + Service, + K: 'static + Sign + Clone + Send + Sync, + HC: 'static + ClientImpl, { let spec = settings.agent().clone(); let env = build_env(spec.env(), hostname, device_id, settings); @@ -683,69 +700,67 @@ fn build_env( env } -fn start_management( +fn start_management( settings: &Settings, - handle: &Handle, mgmt: &DockerModuleRuntime, - id_man: &HubIdentityManager, S, K>, + id_man: &HubIdentityManager, HC, K>, shutdown: Receiver<()>, -) -> Result, Error> +) -> impl Future where - K: 'static + Sign + Clone, - S: 'static + Service, + K: 'static + Sign + Clone + Send + Sync, + HC: 'static + ClientImpl + Send + Sync, { info!("Starting management API..."); let label = "mgmt".to_string(); let url = settings.listen().management_uri().clone(); - let server_handle = handle.clone(); - let service = LoggingService::new( - label, - ApiVersionService::new(ManagementService::new(mgmt, id_man)?), - ); - let run = Http::new() - .bind_handle(url.clone(), server_handle, service)? - .run_until(shutdown.map_err(|_| ())) - .map_err(Error::from); - info!("Listening on {} with 1 thread for management API.", url); - Ok(run) + ManagementService::new(mgmt, id_man) + .map(|service| LoggingService::new(label, ApiVersionService::new(service))) + .and_then(move |service| { + let run = Http::new() + .bind_url(url.clone(), service) + .map_err(failure::Fail::compat)? + .run_until(shutdown.map_err(|_| ())); + info!("Listening on {} with 1 thread for management API.", url); + Ok(run) + }).flatten() } fn start_workload( settings: &Settings, key_store: &K, - handle: &Handle, runtime: &DockerModuleRuntime, shutdown: Receiver<()>, crypto: &C, -) -> Result, Error> +) -> impl Future where - K: 'static + KeyStore + Clone, + K: 'static + KeyStore + Clone + Send + Sync, C: 'static + CreateCertificate + Decrypt + Encrypt + GetTrustBundle + MasterEncryptionKey - + Clone, + + Clone + + Send + + Sync, { info!("Starting workload API..."); let label = "work".to_string(); let url = settings.listen().workload_uri().clone(); - let server_handle = handle.clone(); - let service = LoggingService::new( - label, - ApiVersionService::new(WorkloadService::new(key_store, crypto.clone(), runtime)?), - ); - let run = Http::new() - .bind_handle(url.clone(), server_handle, service)? - .run_until(shutdown.map_err(|_| ())) - .map_err(Error::from); - info!("Listening on {} with 1 thread for workload API.", url); - Ok(run) + WorkloadService::new(key_store, crypto.clone(), runtime) + .map(|service| LoggingService::new(label, ApiVersionService::new(service))) + .and_then(move |service| { + let run = Http::new() + .bind_url(url.clone(), service) + .map_err(failure::Fail::compat)? + .run_until(shutdown.map_err(|_| ())); + info!("Listening on {} with 1 thread for workload API.", url); + Ok(run) + }).flatten() } #[cfg(test)] @@ -815,7 +830,7 @@ mod tests { fn default_settings_raise_unconfigured_error() { let settings = Settings::::new(None).unwrap(); let main = Main::new(settings).unwrap(); - let shutdown_signal = signal::shutdown(&main.handle()); + let shutdown_signal = signal::shutdown(); let result = main.run_until(shutdown_signal); assert_eq!(ErrorKind::Unconfigured, *result.unwrap_err().kind()); @@ -823,7 +838,6 @@ mod tests { #[test] fn settings_first_time_creates_backup() { - let mut core = Core::new().unwrap(); let tmp_dir = TempDir::new("blah").unwrap(); let settings = Settings::::new(Some(SETTINGS)).unwrap(); let config = TestConfig::new("microsoft/test-image".to_string()); @@ -832,17 +846,15 @@ mod tests { TestModule::new("test-module".to_string(), config, Ok(state)); let runtime = TestRuntime::new(Ok(module)); let crypto = TestCrypto {}; - assert_eq!( - check_settings_state( - tmp_dir.path().to_path_buf(), - "settings_state", - &settings, - &runtime, - &mut core, - &crypto - ).unwrap(), - () - ); + let mut tokio_runtime = tokio::runtime::Runtime::new().unwrap(); + check_settings_state( + tmp_dir.path().to_path_buf(), + "settings_state", + &settings, + &runtime, + &crypto, + &mut tokio_runtime, + ).unwrap(); let expected = serde_json::to_string(&settings).unwrap(); let expected_sha = Sha256::digest_str(&expected); let expected_base64 = base64::encode(&expected_sha); @@ -857,7 +869,6 @@ mod tests { #[test] fn settings_change_creates_new_backup() { - let mut core = Core::new().unwrap(); let tmp_dir = TempDir::new("blah").unwrap(); let settings = Settings::::new(Some(SETTINGS)).unwrap(); let config = TestConfig::new("microsoft/test-image".to_string()); @@ -866,17 +877,15 @@ mod tests { TestModule::new("test-module".to_string(), config, Ok(state)); let runtime = TestRuntime::new(Ok(module)); let crypto = TestCrypto {}; - assert_eq!( - check_settings_state( - tmp_dir.path().to_path_buf(), - "settings_state", - &settings, - &runtime, - &mut core, - &crypto - ).unwrap(), - () - ); + let mut tokio_runtime = tokio::runtime::Runtime::new().unwrap(); + check_settings_state( + tmp_dir.path().to_path_buf(), + "settings_state", + &settings, + &runtime, + &crypto, + &mut tokio_runtime, + ).unwrap(); let mut written = String::new(); File::open(tmp_dir.path().join("settings_state")) .unwrap() @@ -884,17 +893,15 @@ mod tests { .unwrap(); let settings1 = Settings::::new(Some(SETTINGS1)).unwrap(); - assert_eq!( - check_settings_state( - tmp_dir.path().to_path_buf(), - "settings_state", - &settings1, - &runtime, - &mut core, - &crypto - ).unwrap(), - () - ); + let mut tokio_runtime = tokio::runtime::Runtime::new().unwrap(); + check_settings_state( + tmp_dir.path().to_path_buf(), + "settings_state", + &settings1, + &runtime, + &crypto, + &mut tokio_runtime, + ).unwrap(); let expected = serde_json::to_string(&settings1).unwrap(); let expected_sha = Sha256::digest_str(&expected); let expected_base64 = base64::encode(&expected_sha); diff --git a/edgelet/iotedged/src/main.rs b/edgelet/iotedged/src/main.rs index 27c63020696..b09f8e641dd 100644 --- a/edgelet/iotedged/src/main.rs +++ b/edgelet/iotedged/src/main.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] extern crate iotedged; diff --git a/edgelet/iotedged/src/signal.rs b/edgelet/iotedged/src/signal.rs index 720e1f5e3b1..c3c055d75b2 100644 --- a/edgelet/iotedged/src/signal.rs +++ b/edgelet/iotedged/src/signal.rs @@ -4,12 +4,11 @@ // https://github.com/runconduit/conduit/blob/master/proxy/src/signal.rs use futures::Future; -use tokio_core::reactor::Handle; type ShutdownSignal = Box + Send>; -pub fn shutdown(handle: &Handle) -> ShutdownSignal { - imp::shutdown(handle) +pub fn shutdown() -> ShutdownSignal { + imp::shutdown() } #[cfg(unix)] @@ -17,14 +16,13 @@ mod imp { use std::fmt; use futures::{future, Future, Stream}; - use tokio_core::reactor::Handle; use tokio_signal::unix::{Signal, SIGINT, SIGTERM}; use super::ShutdownSignal; - pub(super) fn shutdown(handle: &Handle) -> ShutdownSignal { + pub(super) fn shutdown() -> ShutdownSignal { let signals = [SIGINT, SIGTERM].into_iter().map(|&sig| { - Signal::new(sig, handle) + Signal::new(sig) .flatten_stream() .into_future() .map(move |_| { @@ -58,13 +56,12 @@ mod imp { #[cfg(not(unix))] mod imp { use futures::{Future, Stream}; - use tokio_core::reactor::Handle; use tokio_signal; use super::ShutdownSignal; - pub(super) fn shutdown(handle: &Handle) -> ShutdownSignal { - let on_ctrl_c = tokio_signal::ctrl_c(handle) + pub(super) fn shutdown() -> ShutdownSignal { + let on_ctrl_c = tokio_signal::ctrl_c() .flatten_stream() .into_future() .map(|_| { diff --git a/edgelet/iotedged/src/unix.rs b/edgelet/iotedged/src/unix.rs index a97ec92b626..908146af43a 100644 --- a/edgelet/iotedged/src/unix.rs +++ b/edgelet/iotedged/src/unix.rs @@ -8,7 +8,7 @@ pub fn run() -> Result<(), Error> { let settings = app::init()?; let main = super::Main::new(settings)?; - let shutdown_signal = signal::shutdown(&main.handle()); + let shutdown_signal = signal::shutdown(); main.run_until(shutdown_signal)?; Ok(()) } diff --git a/edgelet/iotedged/src/windows.rs b/edgelet/iotedged/src/windows.rs index 22a49c038f7..24964ca9787 100644 --- a/edgelet/iotedged/src/windows.rs +++ b/edgelet/iotedged/src/windows.rs @@ -63,7 +63,7 @@ fn run_as_service(_: Vec) -> Result<(), Error> { info!("Initializing {} service.", IOTEDGED_SERVICE_NAME); let settings = app::init_win_svc()?; let main = super::Main::new(settings)?; - let shutdown_signal = signal::shutdown(&main.handle()) + let shutdown_signal = signal::shutdown() .select(receiver.into_future().map(|_| ()).map_err(|_| ())) .map(|_| ()) .map_err(|_| ()); @@ -86,7 +86,7 @@ pub fn run_as_console() -> Result<(), Error> { let settings = app::init()?; let main = super::Main::new(settings)?; - let shutdown_signal = signal::shutdown(&main.handle()); + let shutdown_signal = signal::shutdown(); main.run_until(shutdown_signal)?; Ok(()) } diff --git a/edgelet/iothubservice/Cargo.toml b/edgelet/iothubservice/Cargo.toml index e1bd547da14..bb87ad82c53 100644 --- a/edgelet/iothubservice/Cargo.toml +++ b/edgelet/iothubservice/Cargo.toml @@ -5,21 +5,20 @@ authors = ["Azure IoT Edge Devs"] publish = false [dependencies] -chrono = "0.4" failure = "0.1" futures = "0.1" -hyper = "0.11" -log = "0.4" +hyper = "0.12" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" url = "1.7" -edgelet-core = { path = "../edgelet-core" } edgelet-http = { path = "../edgelet-http" } edgelet-utils = { path = "../edgelet-utils" } [dev_dependencies] +chrono = "0.4" clap = "2.31" -hyper-tls = "0.1" -tokio-core = "0.1" +hyper-tls = "0.3" +tokio = "0.1.8" +typed-headers = "0.1" diff --git a/edgelet/iothubservice/examples/device.rs b/edgelet/iothubservice/examples/device.rs index 3f92d5cf569..b4d8282b8a8 100644 --- a/edgelet/iothubservice/examples/device.rs +++ b/edgelet/iothubservice/examples/device.rs @@ -13,7 +13,7 @@ extern crate clap; extern crate hyper; extern crate hyper_tls; extern crate serde_json; -extern crate tokio_core; +extern crate tokio; extern crate url; extern crate edgelet_http; @@ -21,13 +21,11 @@ extern crate iothubservice; use chrono::{DateTime, Utc}; use clap::{App, Arg, ArgMatches, SubCommand}; -use hyper::client::Service; -use hyper::{Client as HyperClient, Error as HyperError, Request, Response}; +use hyper::Client as HyperClient; use hyper_tls::HttpsConnector; -use tokio_core::reactor::Core; use url::Url; -use edgelet_http::client::{Client, TokenSource}; +use edgelet_http::client::{Client, ClientImpl, TokenSource}; use edgelet_http::error::Error as HttpError; use iothubservice::error::Error; use iothubservice::DeviceClient; @@ -57,10 +55,7 @@ fn main() { let hub_name = matches.value_of("hub-name").unwrap(); let device_id = matches.value_of("device-id").unwrap(); - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::configure() - .connector(HttpsConnector::new(4, &core.handle()).unwrap()) - .build(&core.handle()); + let hyper_client = HyperClient::builder().build(HttpsConnector::new(4).unwrap()); let token_source = StaticTokenSource::new(sas_token.to_string()); @@ -73,59 +68,78 @@ fn main() { let device_client = DeviceClient::new(client, device_id).unwrap(); + let mut tokio_runtime = tokio::runtime::Runtime::new().unwrap(); + if let Some(_) = matches.subcommand_matches("list") { - list_modules(&mut core, device_client); + list_modules(&mut tokio_runtime, device_client); } else if let Some(create) = matches.subcommand_matches("create") { let module_id = create.value_of("module-id").unwrap(); - create_module(&mut core, device_client, module_id); + create_module(&mut tokio_runtime, device_client, module_id); } else if let Some(delete) = matches.subcommand_matches("delete") { let module_id = delete.value_of("module-id").unwrap(); - delete_module(&mut core, device_client, module_id); + delete_module(&mut tokio_runtime, device_client, module_id); } else if let Some(get) = matches.subcommand_matches("get") { let module_id = get.value_of("module-id").unwrap(); - get_module(&mut core, device_client, module_id); + get_module(&mut tokio_runtime, device_client, module_id); } } -fn list_modules(core: &mut Core, device_client: DeviceClient) -where - S: 'static + Service, +fn list_modules( + tokio_runtime: &mut tokio::runtime::Runtime, + device_client: DeviceClient, +) where + C: 'static + ClientImpl, T: 'static + TokenSource + Clone, T::Error: Into, { - let response = core.run(device_client.list_modules()).unwrap(); + let response = tokio_runtime + .block_on(device_client.list_modules()) + .unwrap(); println!("{}", serde_json::to_string_pretty(&response).unwrap()); } -fn get_module(core: &mut Core, device_client: DeviceClient, module_id: &str) -where - S: 'static + Service, +fn get_module( + tokio_runtime: &mut tokio::runtime::Runtime, + device_client: DeviceClient, + module_id: &str, +) where + C: 'static + ClientImpl, T: 'static + TokenSource + Clone, T::Error: Into, { - let response = core.run(device_client.get_module_by_id(module_id)).unwrap(); + let response = tokio_runtime + .block_on(device_client.get_module_by_id(module_id)) + .unwrap(); println!("{}", serde_json::to_string_pretty(&response).unwrap()); } -fn create_module(core: &mut Core, device_client: DeviceClient, module_id: &str) -where - S: 'static + Service, +fn create_module( + tokio_runtime: &mut tokio::runtime::Runtime, + device_client: DeviceClient, + module_id: &str, +) where + C: 'static + ClientImpl, T: 'static + TokenSource + Clone, T::Error: Into, { - let response = core - .run(device_client.create_module(module_id, None, None)) + let response = tokio_runtime + .block_on(device_client.create_module(module_id, None, None)) .unwrap(); println!("{}", serde_json::to_string_pretty(&response).unwrap()); } -fn delete_module(core: &mut Core, device_client: DeviceClient, module_id: &str) -where - S: 'static + Service, +fn delete_module( + tokio_runtime: &mut tokio::runtime::Runtime, + device_client: DeviceClient, + module_id: &str, +) where + C: 'static + ClientImpl, T: 'static + TokenSource + Clone, T::Error: Into, { - core.run(device_client.delete_module(module_id)).unwrap(); + tokio_runtime + .block_on(device_client.delete_module(module_id)) + .unwrap(); println!("Module {} deleted", module_id); } diff --git a/edgelet/iothubservice/src/device.rs b/edgelet/iothubservice/src/device.rs index 0294f86b1a7..bcdb2e759b6 100644 --- a/edgelet/iothubservice/src/device.rs +++ b/edgelet/iothubservice/src/device.rs @@ -2,30 +2,29 @@ use futures::future::{self, Either}; use futures::Future; -use hyper::client::Service; -use hyper::{Error as HyperError, Method, Request, Response, StatusCode}; +use hyper::{Method, StatusCode}; -use edgelet_http::client::{Client, TokenSource}; +use edgelet_http::client::{Client, ClientImpl, TokenSource}; use edgelet_http::error::{Error as HttpError, ErrorKind as HttpErrorKind}; use error::{Error, ErrorKind}; use model::{AuthMechanism, Module}; -pub struct DeviceClient +pub struct DeviceClient where - S: 'static + Service, + C: ClientImpl, T: TokenSource + Clone, { - client: Client, + client: Client, device_id: String, } -impl DeviceClient +impl DeviceClient where - S: 'static + Service, + C: ClientImpl, T: 'static + TokenSource + Clone, T::Error: Into, { - pub fn new(client: Client, device_id: &str) -> Result, Error> { + pub fn new(client: Client, device_id: &str) -> Result { Ok(DeviceClient { client, device_id: ensure_not_empty!(device_id).to_string(), @@ -79,7 +78,7 @@ where let res = self .client .request::( - Method::Put, + Method::PUT, &format!("/devices/{}/modules/{}", &self.device_id, module_id), None, Some(module), @@ -98,14 +97,14 @@ where let res = self .client .request::<(), Module>( - Method::Get, + Method::GET, &format!("/devices/{}/modules/{}", &self.device_id, module_id), None, None, false, ).map_err(|err| { if let HttpErrorKind::ServiceError(code, _) = err.kind() { - if *code == StatusCode::NotFound { + if *code == StatusCode::NOT_FOUND { return Error::from(ErrorKind::ModuleNotFound); } } @@ -120,7 +119,7 @@ where pub fn list_modules(&self) -> impl Future, Error = Error> { self.client .request::<(), Vec>( - Method::Get, + Method::GET, &format!("/devices/{}/modules", &self.device_id), None, None, @@ -136,7 +135,7 @@ where let res = self .client .request::<(), ()>( - Method::Delete, + Method::DELETE, &format!("/devices/{}/modules/{}", self.device_id, module_id), None, None, @@ -149,9 +148,9 @@ where } } -impl Clone for DeviceClient +impl Clone for DeviceClient where - S: 'static + Service, + C: ClientImpl, T: TokenSource + Clone, { fn clone(&self) -> Self { @@ -169,11 +168,10 @@ mod tests { use chrono::{DateTime, Utc}; use futures::Stream; - use hyper::header::{ContentType, IfMatch}; - use hyper::server::service_fn; - use hyper::{Client as HyperClient, Method}; + use hyper::{self, Body, Client as HyperClient, Method, Request, Response}; use serde_json; - use tokio_core::reactor::Core; + use tokio; + use typed_headers::{mime, ContentType, HeaderMapExt}; use url::Url; use error::ErrorKind; @@ -196,8 +194,7 @@ mod tests { #[test] fn device_client_create_empty_id_fails() { - let core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let client = Client::new( hyper_client, Some(NullTokenSource), @@ -216,8 +213,7 @@ mod tests { #[test] fn device_client_create_white_space_id_fails() { - let core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let client = Client::new( hyper_client, Some(NullTokenSource), @@ -236,8 +232,7 @@ mod tests { #[test] fn module_upsert_empty_module_id_fails() { - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let client = Client::new( hyper_client, Some(NullTokenSource), @@ -260,13 +255,15 @@ mod tests { } }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn module_upsert_white_space_module_id_fails() { - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let client = Client::new( hyper_client, Some(NullTokenSource), @@ -289,12 +286,14 @@ mod tests { } }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn module_upsert_adds_module_body_without_if_match() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); let auth = AuthMechanism::default() @@ -311,46 +310,44 @@ mod tests { .with_managed_by("iotedge".to_string()); let expected_response = module_request.clone().with_generation_id("g1".to_string()); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Put); - assert_eq!(req.path(), "/devices/d1/modules/m1"); - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::PUT); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); let module_request_copy = module_request.clone(); - req.body() + req.into_body() .concat2() .and_then(|req_body| Ok(serde_json::from_slice::(&req_body).unwrap())) .and_then(move |module| { assert_eq!(module, module_request_copy); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body( - serde_json::to_string(&module.with_generation_id("g1".to_string())) - .unwrap() - .into_bytes(), - )) + let mut response = Response::new( + serde_json::to_string(&module.with_generation_id("g1".to_string())) + .unwrap() + .into(), + ); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }) }; - let client = Client::new( - service_fn(handler), - Some(NullTokenSource), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(NullTokenSource), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let task = device_client .upsert_module("m1", Some(auth), Some(&"iotedge".to_string()), false) .then(|result| Ok(assert_eq!(expected_response, result.unwrap())) as Result<(), Error>); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn module_upsert_adds_module_body_with_if_match() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); let auth = AuthMechanism::default() @@ -367,47 +364,45 @@ mod tests { .with_managed_by("iotedge".to_string()); let expected_response = module_request.clone().with_generation_id("g1".to_string()); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Put); - assert_eq!(req.path(), "/devices/d1/modules/m1"); - assert_eq!(req.headers().get::().unwrap(), &IfMatch::Any); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::PUT); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); + assert_eq!(req.headers().get(hyper::header::IF_MATCH).unwrap(), "*"); let module_request_copy = module_request.clone(); - req.body() + req.into_body() .concat2() .and_then(|req_body| Ok(serde_json::from_slice::(&req_body).unwrap())) .and_then(move |module| { assert_eq!(module, module_request_copy); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body( - serde_json::to_string(&module.with_generation_id("g1".to_string())) - .unwrap() - .into_bytes(), - )) + let mut response = Response::new( + serde_json::to_string(&module.with_generation_id("g1".to_string())) + .unwrap() + .into(), + ); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }) }; - let client = Client::new( - service_fn(handler), - Some(NullTokenSource), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(NullTokenSource), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let task = device_client .upsert_module("m1", Some(auth), Some(&"iotedge".to_string()), true) .then(|result| Ok(assert_eq!(expected_response, result.unwrap())) as Result<(), Error>); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn module_delete_empty_module_id_fails() { - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let client = Client::new( hyper_client, Some(NullTokenSource), @@ -427,13 +422,15 @@ mod tests { } }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn module_delete_white_space_module_id_fails() { - let mut core = Core::new().unwrap(); - let hyper_client = HyperClient::new(&core.handle()); + let hyper_client = HyperClient::new(); let client = Client::new( hyper_client, Some(NullTokenSource), @@ -456,40 +453,39 @@ mod tests { } }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn module_delete_request() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Delete); - assert_eq!(req.path(), "/devices/d1/modules/m1"); - assert_eq!(req.headers().get::().unwrap(), &IfMatch::Any); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::DELETE); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); + assert_eq!(req.headers().get(hyper::header::IF_MATCH).unwrap(), "*"); - Ok(Response::new().with_status(StatusCode::Ok)) + Ok(Response::new(Body::empty())) }; - let client = Client::new( - service_fn(handler), - Some(NullTokenSource), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(NullTokenSource), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let task = device_client .delete_module("m1") .then(|result| Ok(assert_eq!(result.unwrap(), ())) as Result<(), Error>); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn modules_list_request() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); let auth = AuthMechanism::default() @@ -515,22 +511,18 @@ mod tests { ]; let expected_modules = modules.clone(); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/devices/d1/modules"); - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/devices/d1/modules"); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body(serde_json::to_string(&modules).unwrap().into_bytes())) + let mut response = Response::new(serde_json::to_string(&modules).unwrap().into()); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }; - let client = Client::new( - service_fn(handler), - Some(NullTokenSource), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(NullTokenSource), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let task = device_client.list_modules().then(|modules| { @@ -542,12 +534,14 @@ mod tests { Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn modules_get_request() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); let auth = AuthMechanism::default() @@ -565,22 +559,18 @@ mod tests { .with_authentication(auth.clone()); let expected_module = module.clone(); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/devices/d1/modules/m1"); - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - Ok(Response::new() - .with_status(StatusCode::Ok) - .with_header(ContentType::json()) - .with_body(serde_json::to_string(&module).unwrap().into_bytes())) + let mut response = Response::new(serde_json::to_string(&module).unwrap().into()); + response + .headers_mut() + .typed_insert(&ContentType(mime::APPLICATION_JSON)); + Ok(response) }; - let client = Client::new( - service_fn(handler), - Some(NullTokenSource), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(NullTokenSource), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let task = device_client.get_module_by_id("m1").then(|module| { @@ -589,28 +579,29 @@ mod tests { Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn modules_get_not_found() { - let mut core = Core::new().unwrap(); let api_version = "2018-04-10"; let host_name = Url::parse("http://localhost").unwrap(); - let handler = move |req: Request| { - assert_eq!(req.method(), &Method::Get); - assert_eq!(req.path(), "/devices/d1/modules/m1"); - assert_eq!(None, req.headers().get::()); + let handler = move |req: Request| { + assert_eq!(req.method(), &Method::GET); + assert_eq!(req.uri().path(), "/devices/d1/modules/m1"); + assert_eq!(None, req.headers().get(hyper::header::IF_MATCH)); - Ok(Response::new().with_status(StatusCode::NotFound)) + let response = Response::builder() + .status(StatusCode::NOT_FOUND) + .body(Body::empty()) + .expect("could not build hyper::Response"); + Ok(response) }; - let client = Client::new( - service_fn(handler), - Some(NullTokenSource), - api_version, - host_name, - ).unwrap(); + let client = Client::new(handler, Some(NullTokenSource), api_version, host_name).unwrap(); let device_client = DeviceClient::new(client, "d1").unwrap(); let task = device_client.get_module_by_id("m1").then(|module| { @@ -620,6 +611,9 @@ mod tests { Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } } diff --git a/edgelet/iothubservice/src/lib.rs b/edgelet/iothubservice/src/lib.rs index 9489380b7c9..a665683a99f 100644 --- a/edgelet/iothubservice/src/lib.rs +++ b/edgelet/iothubservice/src/lib.rs @@ -1,22 +1,22 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] +#[cfg(test)] extern crate chrono; #[macro_use] extern crate failure; extern crate futures; extern crate hyper; -extern crate log; -extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; #[cfg(test)] -extern crate tokio_core; +extern crate tokio; +#[cfg(test)] +extern crate typed_headers; extern crate url; -extern crate edgelet_core; extern crate edgelet_http; #[macro_use] extern crate edgelet_utils; diff --git a/edgelet/management/Cargo.toml b/edgelet/management/Cargo.toml index 6d4eb26c5e3..e0308e449a7 100644 --- a/edgelet/management/Cargo.toml +++ b/edgelet/management/Cargo.toml @@ -12,12 +12,10 @@ api. base64 = "0.9" failure = "0.1" futures = "0.1" -hyper = "0.11" +hyper = "0.12" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" serde_yaml = "0.7" +typed-headers = "0.1" url = "1.5" - -[dev-dependencies] -tokio-core = "*" diff --git a/edgelet/management/src/apis/client.rs b/edgelet/management/src/apis/client.rs index 9943fd1d0a5..986fab6d448 100644 --- a/edgelet/management/src/apis/client.rs +++ b/edgelet/management/src/apis/client.rs @@ -1,24 +1,26 @@ -use std::rc::Rc; +use std::sync::Arc; use super::configuration::Configuration; use hyper; -pub struct APIClient { - configuration: Rc>, +pub struct APIClient { + configuration: Arc>, identity_api: Box<::apis::IdentityApi>, module_api: Box<::apis::ModuleApi>, system_information_api: Box<::apis::SystemInformationApi>, } -impl APIClient { +impl APIClient { pub fn new(configuration: Configuration) -> APIClient { - let rc = Rc::new(configuration); + let configuration = Arc::new(configuration); APIClient { - configuration: rc.clone(), - identity_api: Box::new(::apis::IdentityApiClient::new(rc.clone())), - module_api: Box::new(::apis::ModuleApiClient::new(rc.clone())), - system_information_api: Box::new(::apis::SystemInformationApiClient::new(rc.clone())), + configuration: configuration.clone(), + identity_api: Box::new(::apis::IdentityApiClient::new(configuration.clone())), + module_api: Box::new(::apis::ModuleApiClient::new(configuration.clone())), + system_information_api: Box::new(::apis::SystemInformationApiClient::new( + configuration.clone(), + )), } } diff --git a/edgelet/management/src/apis/configuration.rs b/edgelet/management/src/apis/configuration.rs index 1a7ed340ab0..1ad74064e03 100644 --- a/edgelet/management/src/apis/configuration.rs +++ b/edgelet/management/src/apis/configuration.rs @@ -10,14 +10,14 @@ use failure::err_msg; use failure::Error; -use hyper::client::Connect; +use hyper::client::connect::Connect; use hyper::{Client, Uri}; pub struct Configuration { pub base_path: String, pub user_agent: Option, pub client: Client, - pub uri_composer: Box Result>, + pub uri_composer: Box Result + Send + Sync>, } impl Configuration { diff --git a/edgelet/management/src/apis/identity_api.rs b/edgelet/management/src/apis/identity_api.rs index 8c7d47c4d13..073652522cc 100644 --- a/edgelet/management/src/apis/identity_api.rs +++ b/edgelet/management/src/apis/identity_api.rs @@ -10,28 +10,27 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; - -use hyper::header::{Authorization, UserAgent}; +use typed_headers::{self, http, mime, HeaderMapExt}; use super::{configuration, Error}; -pub struct IdentityApiClient { - configuration: Rc>, +pub struct IdentityApiClient { + configuration: Arc>, } -impl IdentityApiClient { - pub fn new(configuration: Rc>) -> IdentityApiClient { +impl IdentityApiClient { + pub fn new(configuration: Arc>) -> IdentityApiClient { IdentityApiClient { configuration } } } -pub trait IdentityApi { +pub trait IdentityApi: Send + Sync { fn create_identity( &self, api_version: &str, @@ -49,7 +48,12 @@ pub trait IdentityApi { ) -> Box>>; } -impl IdentityApi for IdentityApiClient { +impl IdentityApi for IdentityApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn create_identity( &self, api_version: &str, @@ -58,7 +62,7 @@ impl IdentityApi for IdentityApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Put; + let method = hyper::Method::PUT; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -70,18 +74,21 @@ impl IdentityApi for IdentityApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&identity).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&identity).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -90,9 +97,8 @@ impl IdentityApi for IdentityApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -115,7 +121,7 @@ impl IdentityApi for IdentityApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Delete; + let method = hyper::Method::DELETE; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -127,12 +133,14 @@ impl IdentityApi for IdentityApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -141,9 +149,8 @@ impl IdentityApi for IdentityApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -162,7 +169,7 @@ impl IdentityApi for IdentityApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -174,12 +181,14 @@ impl IdentityApi for IdentityApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -188,9 +197,8 @@ impl IdentityApi for IdentityApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { diff --git a/edgelet/management/src/apis/module_api.rs b/edgelet/management/src/apis/module_api.rs index 925db4f171e..8f61e8a0015 100644 --- a/edgelet/management/src/apis/module_api.rs +++ b/edgelet/management/src/apis/module_api.rs @@ -10,28 +10,27 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; - -use hyper::header::{Authorization, UserAgent}; +use typed_headers::{self, http, mime, HeaderMapExt}; use super::{configuration, Error}; -pub struct ModuleApiClient { - configuration: Rc>, +pub struct ModuleApiClient { + configuration: Arc>, } -impl ModuleApiClient { - pub fn new(configuration: Rc>) -> ModuleApiClient { +impl ModuleApiClient { + pub fn new(configuration: Arc>) -> ModuleApiClient { ModuleApiClient { configuration } } } -pub trait ModuleApi { +pub trait ModuleApi: Send + Sync { fn create_module( &self, api_version: &str, @@ -50,29 +49,29 @@ pub trait ModuleApi { fn list_modules( &self, api_version: &str, - ) -> Box>>; + ) -> Box> + Send>; fn module_logs( &self, api_version: &str, name: &str, follow: bool, tail: &str, - ) -> Box>>; + ) -> Box> + Send>; fn restart_module( &self, api_version: &str, name: &str, - ) -> Box>>; + ) -> Box> + Send>; fn start_module( &self, api_version: &str, name: &str, - ) -> Box>>; + ) -> Box> + Send>; fn stop_module( &self, api_version: &str, name: &str, - ) -> Box>>; + ) -> Box> + Send>; fn update_module( &self, api_version: &str, @@ -81,7 +80,12 @@ pub trait ModuleApi { ) -> Box>>; } -impl ModuleApi for ModuleApiClient { +impl ModuleApi for ModuleApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn create_module( &self, api_version: &str, @@ -89,7 +93,7 @@ impl ModuleApi for ModuleApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -101,18 +105,21 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&module).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&module).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -121,9 +128,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -146,7 +152,7 @@ impl ModuleApi for ModuleApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Delete; + let method = hyper::Method::DELETE; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -158,12 +164,14 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -172,9 +180,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -194,7 +201,7 @@ impl ModuleApi for ModuleApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -206,12 +213,14 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -220,9 +229,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -241,10 +249,10 @@ impl ModuleApi for ModuleApiClient { fn list_modules( &self, api_version: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -256,12 +264,14 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -270,9 +280,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -294,10 +303,10 @@ impl ModuleApi for ModuleApiClient { name: &str, follow: bool, tail: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -311,12 +320,14 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -325,9 +336,9 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); + let (http::response::Parts { status, .. }, body) = resp.into_parts(); if status.is_success() { - Ok(resp.body()) + Ok(body) } else { let b: &[u8] = &[]; Err(Error::from((status, b))) @@ -340,10 +351,10 @@ impl ModuleApi for ModuleApiClient { &self, api_version: &str, name: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -355,12 +366,14 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -369,9 +382,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -388,10 +400,10 @@ impl ModuleApi for ModuleApiClient { &self, api_version: &str, name: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -403,12 +415,14 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -417,9 +431,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -436,10 +449,10 @@ impl ModuleApi for ModuleApiClient { &self, api_version: &str, name: &str, - ) -> Box>> { + ) -> Box> + Send> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -451,12 +464,14 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -465,9 +480,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -488,7 +502,7 @@ impl ModuleApi for ModuleApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Put; + let method = hyper::Method::PUT; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -500,18 +514,21 @@ impl ModuleApi for ModuleApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&module).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&module).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -520,9 +537,8 @@ impl ModuleApi for ModuleApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { diff --git a/edgelet/management/src/apis/system_information_api.rs b/edgelet/management/src/apis/system_information_api.rs index 111be22bba0..fd0669ee782 100644 --- a/edgelet/management/src/apis/system_information_api.rs +++ b/edgelet/management/src/apis/system_information_api.rs @@ -10,44 +10,48 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; - -use hyper::header::{Authorization, UserAgent}; +use typed_headers::{self, http, mime, HeaderMapExt}; use super::{configuration, Error}; -pub struct SystemInformationApiClient { - configuration: Rc>, +pub struct SystemInformationApiClient { + configuration: Arc>, } -impl SystemInformationApiClient { +impl SystemInformationApiClient { pub fn new( - configuration: Rc>, + configuration: Arc>, ) -> SystemInformationApiClient { SystemInformationApiClient { configuration } } } -pub trait SystemInformationApi { +pub trait SystemInformationApi: Send + Sync { fn get_system_info( &self, api_version: &str, ) -> Box>>; } -impl SystemInformationApi for SystemInformationApiClient { +impl SystemInformationApi for SystemInformationApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn get_system_info( &self, api_version: &str, ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -59,12 +63,14 @@ impl SystemInformationApi for SystemInformationApiCli // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -73,9 +79,8 @@ impl SystemInformationApi for SystemInformationApiCli .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { diff --git a/edgelet/management/src/lib.rs b/edgelet/management/src/lib.rs index d3e5661f251..1182b7dd090 100644 --- a/edgelet/management/src/lib.rs +++ b/edgelet/management/src/lib.rs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft. All rights reserved. + +#![deny(unused_extern_crates, warnings)] #![allow(unused_imports, unused_mut, dead_code)] #[macro_use] @@ -9,6 +12,7 @@ extern crate futures; extern crate hyper; extern crate serde; extern crate serde_json; +extern crate typed_headers; extern crate url; pub mod apis; diff --git a/edgelet/provisioning/Cargo.toml b/edgelet/provisioning/Cargo.toml index ef68a2a10d1..4ee31481fa9 100644 --- a/edgelet/provisioning/Cargo.toml +++ b/edgelet/provisioning/Cargo.toml @@ -13,7 +13,6 @@ regex = "0.2" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" -hyper = "0.11" url = "1.7" hsm = { path = "../hsm-rs"} @@ -25,4 +24,4 @@ edgelet-utils = { path = "../edgelet-utils" } [dev_dependencies] tempdir = "0.3.7" -tokio-core = "0.1" +tokio = "0.1.8" diff --git a/edgelet/provisioning/src/lib.rs b/edgelet/provisioning/src/lib.rs index cbacac43a51..44c947f2217 100644 --- a/edgelet/provisioning/src/lib.rs +++ b/edgelet/provisioning/src/lib.rs @@ -1,6 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] +#![deny(unused_extern_crates, warnings)] extern crate base64; extern crate bytes; @@ -8,18 +8,16 @@ extern crate bytes; extern crate failure; extern crate futures; extern crate hsm; -extern crate hyper; #[macro_use] extern crate log; extern crate regex; -extern crate serde; #[macro_use] extern crate serde_derive; extern crate serde_json; #[cfg(test)] extern crate tempdir; #[cfg(test)] -extern crate tokio_core; +extern crate tokio; extern crate url; extern crate dps; diff --git a/edgelet/provisioning/src/provisioning.rs b/edgelet/provisioning/src/provisioning.rs index fe0fab24611..36bc4e01c03 100644 --- a/edgelet/provisioning/src/provisioning.rs +++ b/edgelet/provisioning/src/provisioning.rs @@ -10,8 +10,6 @@ use bytes::Bytes; use futures::future::Either; use futures::{future, Future}; -use hyper::client::Service; -use hyper::{Error as HyperError, Request, Response}; use regex::RegexSet; use serde_json; use url::Url; @@ -19,7 +17,7 @@ use url::Url; use dps::registration::{DpsClient, DpsTokenSource}; use edgelet_core::crypto::{Activate, KeyIdentity, KeyStore, MemoryKey, MemoryKeyStore}; use edgelet_hsm::tpm::{TpmKey, TpmKeyStore}; -use edgelet_http::client::Client as HttpClient; +use edgelet_http::client::{Client as HttpClient, ClientImpl}; use edgelet_utils::log_failure; use error::{Error, ErrorKind}; use hsm::TpmKey as HsmTpmKey; @@ -61,7 +59,7 @@ pub trait Provision { fn provision( self, key_activator: Self::Hsm, - ) -> Box>; + ) -> Box + Send>; } #[derive(Debug)] @@ -125,7 +123,7 @@ impl Provision for ManualProvisioning { fn provision( self, mut key_activator: Self::Hsm, - ) -> Box> { + ) -> Box + Send> { let ManualProvisioning { key, device_id, @@ -147,32 +145,32 @@ impl Provision for ManualProvisioning { } } -pub struct DpsProvisioning +pub struct DpsProvisioning where - S: 'static + Service, + C: ClientImpl, { - client: HttpClient>, + client: HttpClient>, scope_id: String, registration_id: String, hsm_tpm_ek: HsmTpmKey, hsm_tpm_srk: HsmTpmKey, } -impl DpsProvisioning +impl DpsProvisioning where - S: 'static + Service, + C: ClientImpl, { pub fn new( - service: S, + client_impl: C, endpoint: Url, scope_id: String, registration_id: String, api_version: &str, hsm_tpm_ek: HsmTpmKey, hsm_tpm_srk: HsmTpmKey, - ) -> Result, Error> { + ) -> Result { let client = HttpClient::new( - service, + client_impl, None as Option>, &api_version, endpoint, @@ -189,16 +187,16 @@ where } } -impl Provision for DpsProvisioning +impl Provision for DpsProvisioning where - S: 'static + Service, + C: 'static + ClientImpl, { type Hsm = TpmKeyStore; fn provision( self, key_activator: Self::Hsm, - ) -> Box> { + ) -> Box + Send> { let d = DpsClient::new( self.client.clone(), self.scope_id.clone(), @@ -277,7 +275,7 @@ where fn provision( self, key_activator: Self::Hsm, - ) -> Box> { + ) -> Box + Send> { let path = self.path.clone(); let path_on_err = self.path.clone(); Box::new( @@ -303,7 +301,7 @@ mod tests { use super::*; use tempdir::TempDir; - use tokio_core::reactor::Core; + use tokio; use error::ErrorKind; @@ -315,7 +313,7 @@ mod tests { fn provision( self, _key_activator: Self::Hsm, - ) -> Box> { + ) -> Box + Send> { Box::new(future::ok(ProvisioningResult { device_id: "TestDevice".to_string(), hub_name: "TestHub".to_string(), @@ -332,14 +330,13 @@ mod tests { fn provision( self, _key_activator: Self::Hsm, - ) -> Box> { + ) -> Box + Send> { Box::new(future::err(Error::from(ErrorKind::Dps))) } } #[test] fn manual_get_credentials_success() { - let mut core = Core::new().unwrap(); let provisioning = ManualProvisioning::new("HostName=test.com;DeviceId=test;SharedAccessKey=test"); assert_eq!(provisioning.is_ok(), true); @@ -357,7 +354,10 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] @@ -368,7 +368,6 @@ mod tests { #[test] fn connection_string_split_success() { - let mut core = Core::new().unwrap(); let provisioning = ManualProvisioning::new("HostName=test.com;DeviceId=test;SharedAccessKey=test"); assert_eq!(provisioning.is_ok(), true); @@ -386,7 +385,10 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); let provisioning1 = ManualProvisioning::new("DeviceId=test;SharedAccessKey=test;HostName=test.com"); @@ -404,12 +406,14 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task1).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task1) + .unwrap(); } #[test] fn connection_string_split_error() { - let mut core = Core::new().unwrap(); let test1 = ManualProvisioning::new("DeviceId=test;SharedAccessKey=test"); assert_eq!(test1.is_err(), true); let test2 = ManualProvisioning::new( @@ -427,12 +431,14 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task1).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task1) + .unwrap(); } #[test] fn backup_success() { - let mut core = Core::new().unwrap(); let test_provisioner = TestProvisioning {}; let tmp_dir = TempDir::new("backup").unwrap(); let file_path = tmp_dir.path().join("dps_backup.json"); @@ -453,19 +459,24 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); } #[test] fn restore_success() { - let mut core = Core::new().unwrap(); let test_provisioner = TestProvisioning {}; let tmp_dir = TempDir::new("backup").unwrap(); let file_path = tmp_dir.path().join("dps_backup.json"); let file_path_clone = file_path.clone(); let prov_wrapper = BackupProvisioning::new(test_provisioner, file_path); let task = prov_wrapper.provision(MemoryKeyStore::new()); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); let prov_wrapper_err = BackupProvisioning::new(TestProvisioningWithError {}, file_path_clone); @@ -482,19 +493,24 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task1).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task1) + .unwrap(); } #[test] fn restore_failure() { - let mut core = Core::new().unwrap(); let test_provisioner = TestProvisioning {}; let tmp_dir = TempDir::new("backup").unwrap(); let file_path = tmp_dir.path().join("dps_backup.json"); let file_path_wrong = tmp_dir.path().join("dps_backup_wrong.json"); let prov_wrapper = BackupProvisioning::new(test_provisioner, file_path); let task = prov_wrapper.provision(MemoryKeyStore::new()); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); let prov_wrapper_err = BackupProvisioning::new(TestProvisioningWithError {}, file_path_wrong); @@ -507,7 +523,10 @@ mod tests { } Ok(()) as Result<(), Error> }); - core.run(task1).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task1) + .unwrap(); } #[test] diff --git a/edgelet/systemd/src/lib.rs b/edgelet/systemd/src/lib.rs index 528a78835a5..56ca769df07 100644 --- a/edgelet/systemd/src/lib.rs +++ b/edgelet/systemd/src/lib.rs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. +#![deny(unused_extern_crates, warnings)] + extern crate failure; #[macro_use] extern crate failure_derive; diff --git a/edgelet/systemd/src/linux.rs b/edgelet/systemd/src/linux.rs index 59359ab15f0..cb3aa2f0668 100644 --- a/edgelet/systemd/src/linux.rs +++ b/edgelet/systemd/src/linux.rs @@ -215,6 +215,7 @@ fn is_socket_unix( mod tests { use super::*; + use std::panic; use std::sync::{Mutex, MutexGuard}; use nix::unistd; @@ -282,8 +283,21 @@ mod tests { } #[test] - #[should_panic(expected = "LISTEN_FDNAMES")] fn test_listen_fds_with_missing_env() { - listen_fds_with_names(true, 3).unwrap(); + let r = { + let _l = lock_env(); + panic::catch_unwind(|| listen_fds_with_names(true, 3).unwrap()) + }; + + match r { + Ok(_) => panic!("expected listen_fds_with_names to panic"), + Err(err) => match err.downcast_ref::().map(String::as_str) { + Some(s) if s.contains(ENV_NAMES) => (), + other => panic!( + "expected listen_fds_with_names to panic with {} but it panicked with {:?}", + ENV_NAMES, other + ), + }, + } } } diff --git a/edgelet/tokio-named-pipe/Cargo.toml b/edgelet/tokio-named-pipe/Cargo.toml index f5800c1201f..cd387e66f80 100644 --- a/edgelet/tokio-named-pipe/Cargo.toml +++ b/edgelet/tokio-named-pipe/Cargo.toml @@ -5,11 +5,9 @@ authors = ["Azure IoT Edge Devs"] publish = false [target.'cfg(windows)'.dependencies] -bytes = "0.4" futures = "0.1" mio-named-pipes = "0.1" -tokio-core = "0.1" -tokio-io = "0.1" +tokio = "0.1" winapi = { version = "0.3.5", features = ["namedpipeapi"] } [dev-dependencies] diff --git a/edgelet/tokio-named-pipe/src/lib.rs b/edgelet/tokio-named-pipe/src/lib.rs index 00571699814..a5eab3f4a00 100644 --- a/edgelet/tokio-named-pipe/src/lib.rs +++ b/edgelet/tokio-named-pipe/src/lib.rs @@ -1,13 +1,11 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] #![cfg(windows)] +#![deny(unused_extern_crates, warnings)] -extern crate bytes; extern crate futures; extern crate mio_named_pipes; -extern crate tokio_core; -extern crate tokio_io; +extern crate tokio; extern crate winapi; use std::convert::AsRef; @@ -18,11 +16,10 @@ use std::os::windows::prelude::*; use std::path::Path; use std::time::Duration; -use bytes::{Buf, BufMut}; -use futures::{Async, Poll}; +use futures::Poll; use mio_named_pipes::NamedPipe; -use tokio_core::reactor::{Handle, PollEvented}; -use tokio_io::{AsyncRead, AsyncWrite}; +use tokio::io::{AsyncRead, AsyncWrite}; +use tokio::reactor::PollEvented2; use winapi::um::namedpipeapi::WaitNamedPipeW; use winapi::um::winbase::*; @@ -31,15 +28,11 @@ const PIPE_WAIT_TIMEOUT_MS: u32 = 10 * 1000; #[derive(Debug)] pub struct PipeStream { - io: PollEvented, + io: PollEvented2, } impl PipeStream { - pub fn connect>( - path: P, - handle: &Handle, - timeout: Option, - ) -> io::Result { + pub fn connect>(path: P, timeout: Option) -> io::Result { let timeout = timeout .map(|t| (t.as_secs() as u32) + t.subsec_millis()) .unwrap_or(PIPE_WAIT_TIMEOUT_MS); @@ -69,7 +62,6 @@ impl PipeStream { } return PipeStream::connect( path, - handle, Some(Duration::from_millis(u64::from(timeout))), ); } @@ -81,25 +73,17 @@ impl PipeStream { let named_pipe = unsafe { NamedPipe::from_raw_handle(file.into_raw_handle()) }; Ok(PipeStream { - io: PollEvented::new(named_pipe, handle)?, + io: PollEvented2::new(named_pipe), }) } } } - pub fn poll_read(&self) -> Async<()> { - self.io.poll_read() - } - - pub fn poll_write(&self) -> Async<()> { - self.io.poll_write() - } - pub fn disconnect(&self) -> io::Result<()> { self.io.get_ref().disconnect() } - pub fn io_mut(&mut self) -> &mut PollEvented { + pub fn io_mut(&mut self) -> &mut PollEvented2 { &mut self.io } } @@ -140,54 +124,10 @@ impl AsyncRead for PipeStream { unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { false } - - fn read_buf(&mut self, buf: &mut B) -> Poll { - if let Async::NotReady = ::poll_read(self) { - return Ok(Async::NotReady); - } - - unsafe { - match self.io_mut().get_mut().read(buf.bytes_mut()) { - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - self.io.need_read(); - Ok(Async::NotReady) - } else { - Err(e) - } - } - Ok(size) => { - buf.advance_mut(size); - Ok(size.into()) - } - } - } - } } impl AsyncWrite for PipeStream { fn shutdown(&mut self) -> Poll<(), io::Error> { Ok(().into()) } - - fn write_buf(&mut self, buf: &mut B) -> Poll { - if let Async::NotReady = ::poll_write(self) { - return Ok(Async::NotReady); - } - - match self.io_mut().get_mut().write(buf.bytes()) { - Err(e) => { - if e.kind() == io::ErrorKind::WouldBlock { - self.io.need_write(); - Ok(Async::NotReady) - } else { - Err(e) - } - } - Ok(size) => { - buf.advance(size); - Ok(size.into()) - } - } - } } diff --git a/edgelet/tokio-named-pipe/tests/smoke.rs b/edgelet/tokio-named-pipe/tests/smoke.rs index 09004b0ae11..c6ceb3d5d88 100644 --- a/edgelet/tokio-named-pipe/tests/smoke.rs +++ b/edgelet/tokio-named-pipe/tests/smoke.rs @@ -7,8 +7,7 @@ extern crate futures; extern crate mio; extern crate mio_named_pipes; extern crate rand; -extern crate tokio_core; -extern crate tokio_io; +extern crate tokio; extern crate tokio_named_pipe; @@ -21,9 +20,8 @@ use futures::Future; use mio::{Events, Poll, PollOpt, Ready, Token}; use mio_named_pipes::NamedPipe; use rand::Rng; -use tokio_core::reactor::Core; -use tokio_io::codec::{FramedRead, FramedWrite, LinesCodec}; -use tokio_io::io as tio; +use tokio::codec::{FramedRead, FramedWrite, LinesCodec}; +use tokio::io as tio; use tokio_named_pipe::PipeStream; @@ -46,15 +44,13 @@ fn server() -> (NamedPipe, String) { #[test] #[should_panic(expected = "The system cannot find the file specified")] fn connect_invalid_path() { - let core = Core::new().unwrap(); - let _stream = PipeStream::connect(r"\\.\pipe\boo", &core.handle(), None).unwrap(); + let _stream = PipeStream::connect(r"\\.\pipe\boo", None).unwrap(); } #[test] fn connect_succeeds() { - let core = Core::new().unwrap(); let (_server, path) = server(); - let _stream = PipeStream::connect(path, &core.handle(), None).unwrap(); + let _stream = PipeStream::connect(path, None).unwrap(); } #[test] @@ -62,8 +58,7 @@ fn read_data() { let data = b"cow say moo"; let (mut server, path) = server(); - let mut core = Core::new().unwrap(); - let stream = PipeStream::connect(path, &core.handle(), None).unwrap(); + let stream = PipeStream::connect(path, None).unwrap(); let poll = t!(Poll::new()); t!(poll.register( @@ -77,10 +72,12 @@ fn read_data() { assert_eq!(t!(server.write(data)), data.len()); let buf = [0; 11]; - let task = tio::read(stream, buf); + let task = tio::read_exact(stream, buf); - let (_, read_data, read_len) = core.run(task).unwrap(); - assert_eq!(read_len, data.len()); + let (_, read_data) = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); for i in 0..read_data.len() { assert_eq!(read_data[i], data[i]); } @@ -89,11 +86,13 @@ fn read_data() { #[test] fn write_data() { let (mut server, path) = server(); - let mut core = Core::new().unwrap(); - let stream = PipeStream::connect(path, &core.handle(), None).unwrap(); + let stream = PipeStream::connect(path, None).unwrap(); let write_future = tio::write_all(stream, b"cow say moo"); - core.run(write_future).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(write_future) + .unwrap(); let poll = t!(Poll::new()); t!(poll.register( @@ -125,8 +124,7 @@ fn read_async() { let data = "cow say moo\nsheep say baa\n".as_bytes(); let (mut server, path) = server(); - let mut core = Core::new().unwrap(); - let stream = PipeStream::connect(path, &core.handle(), None).unwrap(); + let stream = PipeStream::connect(path, None).unwrap(); let poll = t!(Poll::new()); t!(poll.register( @@ -147,7 +145,10 @@ fn read_async() { .map(|(line2, _)| (line1.unwrap(), line2.unwrap())) }); - let result = core.run(task).unwrap(); + let result = tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); assert_eq!( result, ("cow say moo".to_string(), "sheep say baa".to_string()) @@ -157,14 +158,16 @@ fn read_async() { #[test] fn write_async() { let (mut server, path) = server(); - let mut core = Core::new().unwrap(); - let stream = PipeStream::connect(path, &core.handle(), None).unwrap(); + let stream = PipeStream::connect(path, None).unwrap(); let framed_write = FramedWrite::new(stream, LinesCodec::new()); let task = framed_write .send("cow say moo".to_string()) .and_then(|sink| sink.send("sheep say baa".to_string())); - core.run(task).unwrap(); + tokio::runtime::current_thread::Runtime::new() + .unwrap() + .block_on(task) + .unwrap(); let poll = t!(Poll::new()); t!(poll.register( diff --git a/edgelet/win-logger/src/lib.rs b/edgelet/win-logger/src/lib.rs index f8277a62de2..7630dd2d62a 100644 --- a/edgelet/win-logger/src/lib.rs +++ b/edgelet/win-logger/src/lib.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft. All rights reserved. -#![deny(warnings)] #![cfg(windows)] +#![deny(unused_extern_crates, warnings)] #[macro_use] extern crate failure; diff --git a/edgelet/workload/Cargo.toml b/edgelet/workload/Cargo.toml index 308f49f26d3..9a925987a2e 100644 --- a/edgelet/workload/Cargo.toml +++ b/edgelet/workload/Cargo.toml @@ -8,12 +8,10 @@ publish = false base64 = "0.9" failure = "0.1" futures = "0.1" -hyper = "0.11" +hyper = "0.12" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" serde_yaml = "0.7" +typed-headers = "0.1" url = "1.5" - -[dev-dependencies] -tokio-core = "*" diff --git a/edgelet/workload/src/apis/client.rs b/edgelet/workload/src/apis/client.rs index ec6634a3e97..690b7752814 100644 --- a/edgelet/workload/src/apis/client.rs +++ b/edgelet/workload/src/apis/client.rs @@ -1,20 +1,20 @@ -use std::rc::Rc; +use std::sync::Arc; use super::configuration::Configuration; use hyper; -pub struct APIClient { - configuration: Rc>, +pub struct APIClient { + configuration: Arc>, workload_api: Box<::apis::WorkloadApi>, } -impl APIClient { +impl APIClient { pub fn new(configuration: Configuration) -> APIClient { - let rc = Rc::new(configuration); + let configuration = Arc::new(configuration); APIClient { - configuration: rc.clone(), - workload_api: Box::new(::apis::WorkloadApiClient::new(rc.clone())), + configuration: configuration.clone(), + workload_api: Box::new(::apis::WorkloadApiClient::new(configuration.clone())), } } diff --git a/edgelet/workload/src/apis/configuration.rs b/edgelet/workload/src/apis/configuration.rs index 5e12685997f..9e5e2ec8fe7 100644 --- a/edgelet/workload/src/apis/configuration.rs +++ b/edgelet/workload/src/apis/configuration.rs @@ -10,7 +10,7 @@ use failure::err_msg; use failure::Error; -use hyper::client::Connect; +use hyper::client::connect::Connect; use hyper::{Client, Uri}; pub struct Configuration { diff --git a/edgelet/workload/src/apis/workload_api.rs b/edgelet/workload/src/apis/workload_api.rs index 07628d56029..17aa9e3df67 100644 --- a/edgelet/workload/src/apis/workload_api.rs +++ b/edgelet/workload/src/apis/workload_api.rs @@ -10,23 +10,22 @@ use std::borrow::Borrow; use std::borrow::Cow; -use std::rc::Rc; +use std::sync::Arc; use futures; use futures::{Future, Stream}; use hyper; use serde_json; - -use hyper::header::{Authorization, UserAgent}; +use typed_headers::{self, http, mime, HeaderMapExt}; use super::{configuration, Error}; -pub struct WorkloadApiClient { - configuration: Rc>, +pub struct WorkloadApiClient { + configuration: Arc>, } -impl WorkloadApiClient { - pub fn new(configuration: Rc>) -> WorkloadApiClient { +impl WorkloadApiClient { + pub fn new(configuration: Arc>) -> WorkloadApiClient { WorkloadApiClient { configuration } } } @@ -72,7 +71,12 @@ pub trait WorkloadApi { ) -> Box>>; } -impl WorkloadApi for WorkloadApiClient { +impl WorkloadApi for WorkloadApiClient +where + C: hyper::client::connect::Connect + 'static, + ::Transport: 'static, + ::Future: 'static, +{ fn create_identity_certificate( &self, api_version: &str, @@ -81,7 +85,7 @@ impl WorkloadApi for WorkloadApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -98,12 +102,14 @@ impl WorkloadApi for WorkloadApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -112,9 +118,8 @@ impl WorkloadApi for WorkloadApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -140,7 +145,7 @@ impl WorkloadApi for WorkloadApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -157,18 +162,21 @@ impl WorkloadApi for WorkloadApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&request).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&request).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -177,9 +185,8 @@ impl WorkloadApi for WorkloadApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -205,7 +212,7 @@ impl WorkloadApi for WorkloadApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -222,18 +229,21 @@ impl WorkloadApi for WorkloadApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&payload).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&payload).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); + req.headers_mut() + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -242,9 +252,8 @@ impl WorkloadApi for WorkloadApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -270,7 +279,7 @@ impl WorkloadApi for WorkloadApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -287,18 +296,21 @@ impl WorkloadApi for WorkloadApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&payload).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&payload).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -307,9 +319,8 @@ impl WorkloadApi for WorkloadApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -335,7 +346,7 @@ impl WorkloadApi for WorkloadApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Post; + let method = hyper::Method::POST; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -352,18 +363,21 @@ impl WorkloadApi for WorkloadApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); + let serialized = serde_json::to_string(&payload).unwrap(); + let serialized_len = serialized.len(); + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } - - let serialized = serde_json::to_string(&payload).unwrap(); - req.headers_mut().set(hyper::header::ContentType::json()); + let mut req = req + .body(hyper::Body::from(serialized)) + .expect("could not build hyper::Request"); req.headers_mut() - .set(hyper::header::ContentLength(serialized.len() as u64)); - req.set_body(serialized); + .typed_insert(&typed_headers::ContentType(mime::APPLICATION_JSON)); + req.headers_mut() + .typed_insert(&typed_headers::ContentLength(serialized_len as u64)); // send request Box::new( @@ -372,9 +386,8 @@ impl WorkloadApi for WorkloadApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { @@ -396,7 +409,7 @@ impl WorkloadApi for WorkloadApiClient { ) -> Box>> { let configuration: &configuration::Configuration = self.configuration.borrow(); - let method = hyper::Method::Get; + let method = hyper::Method::GET; let query = ::url::form_urlencoded::Serializer::new(String::new()) .append_pair("api-version", &api_version.to_string()) @@ -408,12 +421,14 @@ impl WorkloadApi for WorkloadApiClient { // if let Err(e) = uri { // return Box::new(futures::future::err(e)); // } - let mut req = hyper::Request::new(method, uri.unwrap()); - + let mut req = hyper::Request::builder(); + req.method(method).uri(uri.unwrap()); if let Some(ref user_agent) = configuration.user_agent { - req.headers_mut() - .set(UserAgent::new(Cow::Owned(user_agent.clone()))); + req.header(http::header::USER_AGENT, &**user_agent); } + let req = req + .body(hyper::Body::empty()) + .expect("could not build hyper::Request"); // send request Box::new( @@ -422,9 +437,8 @@ impl WorkloadApi for WorkloadApiClient { .request(req) .map_err(Error::from) .and_then(|resp| { - let status = resp.status(); - resp.body() - .concat2() + let (http::response::Parts { status, .. }, body) = resp.into_parts(); + body.concat2() .and_then(move |body| Ok((status, body))) .map_err(Error::from) }).and_then(|(status, body)| { diff --git a/edgelet/workload/src/lib.rs b/edgelet/workload/src/lib.rs index d3e5661f251..1182b7dd090 100644 --- a/edgelet/workload/src/lib.rs +++ b/edgelet/workload/src/lib.rs @@ -1,3 +1,6 @@ +// Copyright (c) Microsoft. All rights reserved. + +#![deny(unused_extern_crates, warnings)] #![allow(unused_imports, unused_mut, dead_code)] #[macro_use] @@ -9,6 +12,7 @@ extern crate futures; extern crate hyper; extern crate serde; extern crate serde_json; +extern crate typed_headers; extern crate url; pub mod apis;